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/core.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
export { A as AlongFade, C as Circle, a as CircleLayerSpec, b as CircleOptions, D as DEFAULT_FOG, d as DEFAULT_LIGHT, e as DEFAULT_MAPLIBRE_LIGHT, f as DEFAULT_SKY, E as EARTH_CIRCUMFERENCE, F as FOG_CUTOFF_MIN_M, i as FitViewport, G as GLOBE_MAX_PITCH, k as GLOBE_ZOOM_MAX, l as GLOBE_ZOOM_MIN, H as HeatmapLayerSpec, L as LayerSpecV2, n as LiftAt, M as MAX_LATITUDE, t as MODEL_VERTEX_STRIDE, w as MapObjectOptions, y as ModelLayerSpec, z as ModelLayout, K as ModelOptions, N as ModelPrimitive, O as OSMGL_FORMAT_VERSION, P as OSMGL_VERSION_KEY, Q as ObjectPaint, R as ObjectPart, T as PITCH_BY_ZOOM, V as Polygon, W as PolygonOptions, X as Polyline, Y as PolylineOptions, Z as PolylineSegment, $ as RUNTIME_FILL_STRIDE, a0 as RUNTIME_LINE_STRIDE, a1 as RouteArea, a2 as RouteAreaOptions, a3 as RuntimeMesh, aa as TILE_SIZE, af as alongFadeFactor, ag as altitudeFromMercatorZ, ah as buildRuntimeFill, ai as buildRuntimeLine, aj as cameraForBounds, ak as circumferenceAtLatitude, al as clampLat, am as distToSegment, an as globeBasis, ao as globeFlatMix, ap as globeRadius, aq as globeToLocal, ar as isDemLayer, as as isOsmglV2, at as latFromMercatorY, au as layerV1toV2, av as lngFromMercatorX, aw as lngLatToUnit, ax as mercatorMetersPerTile, ay as mercatorX, az as mercatorY, aA as mercatorZFromAltitude, aB as metersPerPixel, aC as metersPerTile, aD as parseGlb, aE as parseGlbAsync, aF as pitchLimitAt, aG as pixelsPerMeter, aH as pointInRing, aI as propertyV2toV1, aJ as raySphere, aK as styleV1toV2, aL as themeToInternal, aM as themeV1toV2, aN as tileOriginMeters, aO as toLngLat, aP as toMapLibreStyle, aQ as toPoint, aR as unitToLngLat, aS as worldSize } from './model-mshqbG69.js';
|
|
3
|
-
import { b as VectorTileLayer, P as PropValue, G as GeomType, k as Ring, R as RoadName } from './speed-index-kbbQG2xX.js';
|
|
4
|
-
export { V as VectorTile, a as VectorTileFeature, s as splitPolygons } from './speed-index-kbbQG2xX.js';
|
|
5
|
-
import 'pbf';
|
|
1
|
+
import Pbf from 'pbf';
|
|
6
2
|
|
|
7
3
|
type Listener<T = unknown> = (payload: T) => void;
|
|
8
4
|
/** Базовый источник событий движка: Map, source'ы и слои наследуются от него. */
|
|
@@ -15,6 +11,865 @@ declare class Evented<Events extends Record<string, unknown> = Record<string, un
|
|
|
15
11
|
removeAllListeners(): void;
|
|
16
12
|
}
|
|
17
13
|
|
|
14
|
+
declare const TILE_SIZE = 512;
|
|
15
|
+
declare const EARTH_CIRCUMFERENCE = 40075016.686;
|
|
16
|
+
/** За этой широтой меркатор уходит в бесконечность; тот же предел, что у тайловых схем. */
|
|
17
|
+
declare const MAX_LATITUDE = 85.051129;
|
|
18
|
+
interface LngLat {
|
|
19
|
+
lng: number;
|
|
20
|
+
lat: number;
|
|
21
|
+
}
|
|
22
|
+
type LngLatLike = LngLat | [number, number];
|
|
23
|
+
declare function toLngLat(v: LngLatLike): LngLat;
|
|
24
|
+
declare const worldSize: (zoom: number) => number;
|
|
25
|
+
declare const clampLat: (lat: number) => number;
|
|
26
|
+
/** Долгота → нормализованный меркатор [0..1]. */
|
|
27
|
+
declare function mercatorX(lng: number): number;
|
|
28
|
+
/** Широта → нормализованный меркатор [0..1], север сверху. */
|
|
29
|
+
declare function mercatorY(lat: number): number;
|
|
30
|
+
declare function lngFromMercatorX(x: number): number;
|
|
31
|
+
declare function latFromMercatorY(y: number): number;
|
|
32
|
+
/** Длина окружности Земли на данной широте — база для перевода метров в пиксели. */
|
|
33
|
+
declare function circumferenceAtLatitude(lat: number): number;
|
|
34
|
+
/** Метры высоты → нормализованные меркаторные единицы (та же шкала, что x/y). */
|
|
35
|
+
declare function mercatorZFromAltitude(altitudeMeters: number, lat: number): number;
|
|
36
|
+
declare function altitudeFromMercatorZ(z: number, lat: number): number;
|
|
37
|
+
/** Сколько мировых пикселей в одном метре на данной широте и зуме. */
|
|
38
|
+
declare function pixelsPerMeter(lat: number, zoom: number): number;
|
|
39
|
+
/** Сколько метров в одном экранном пикселе — для порогов упрощения геометрии. */
|
|
40
|
+
declare function metersPerPixel(lat: number, zoom: number): number;
|
|
41
|
+
/**
|
|
42
|
+
* Ширина тайла в метрах на широте его центра.
|
|
43
|
+
*
|
|
44
|
+
* Нужна там, где решение принимается в МЕТРАХ, а данные приходят в единицах
|
|
45
|
+
* тайла: скатная крыша ставится по размеру дома, рисунок фасада — по высоте
|
|
46
|
+
* этажа. В единицах тайла один и тот же порог означал бы разные здания на
|
|
47
|
+
* разных зумах и широтах.
|
|
48
|
+
*/
|
|
49
|
+
declare function metersPerTile(z: number, y: number): number;
|
|
50
|
+
/**
|
|
51
|
+
* Ширина тайла в МЕРКАТОРНЫХ метрах — одинаковая для всех тайлов зума.
|
|
52
|
+
*
|
|
53
|
+
* ★ Это и есть система координат процедурного рисунка. `metersPerTile` берёт
|
|
54
|
+
* широту СВОЕГО тайла, и потому не годится: у соседей по вертикали ширина тайла
|
|
55
|
+
* отличается (на z18 — на 1,8 мм), а начало координат считается как `x × ширина`,
|
|
56
|
+
* где x это сотни тысяч. Полтора миллиметра, умноженные на 181 тысячу, дают
|
|
57
|
+
* ТРИСТА МЕТРОВ расхождения — рисунок на горизонтальном шве не просто съезжает,
|
|
58
|
+
* он оказывается в другом месте волны, и шов виден как разрез. Меркаторные метры
|
|
59
|
+
* от широты не зависят, поэтому непрерывны и по x, и по y, и между зумами
|
|
60
|
+
* (у родителя вдвое шире, а x вдвое меньше — начало то же).
|
|
61
|
+
*
|
|
62
|
+
* Цена: меркаторный метр на широте 38° длиннее настоящего в 1/cos. Обратно в
|
|
63
|
+
* настоящие переводит делитель по широте ЦЕНТРА КАРТЫ
|
|
64
|
+
* (`LayerRenderer.patternScale`) — делятся и масштаб, и начало, поэтому размеры
|
|
65
|
+
* рисунков остаются прежними, а непрерывность точной. Делитель обязан быть
|
|
66
|
+
* общим на кадр: возьми его по широте тайла — швы вернутся.
|
|
67
|
+
*/
|
|
68
|
+
declare function mercatorMetersPerTile(z: number): number;
|
|
69
|
+
/**
|
|
70
|
+
* Начало тайла в меркаторных метрах — чтобы процедурный рисунок был СКВОЗНЫМ.
|
|
71
|
+
*
|
|
72
|
+
* Материалы и кровли считаются от координаты в метрах. Если брать её внутри
|
|
73
|
+
* тайла, рисунок начинается заново на каждой границе, и по швам тайлов идут
|
|
74
|
+
* отчётливые полосы — их видно на любой заливке с рисунком.
|
|
75
|
+
*
|
|
76
|
+
* Полную мировую координату во Float32 не отдать: на экваторе это 4·10⁷ метров,
|
|
77
|
+
* где шаг float — метры. Поэтому берём остаток от 65536 м: соседние тайлы
|
|
78
|
+
* по-прежнему отличаются ровно на свою ширину, точность остаётся миллиметровой,
|
|
79
|
+
* а разрыв случается раз в 65 километров — там, где его никто не увидит.
|
|
80
|
+
*/
|
|
81
|
+
declare function tileOriginMeters(z: number, x: number, y: number): [number, number];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Прямоугольник по координатам.
|
|
85
|
+
*
|
|
86
|
+
* Нужен ровно для одного — «покажи это целиком»: маршрут, выдачу поиска,
|
|
87
|
+
* границу района. Имена методов те же, что у Mapbox и MapLibre (`extend`,
|
|
88
|
+
* `getCenter`, `contains`), чтобы чужой код переносился без переписывания.
|
|
89
|
+
*
|
|
90
|
+
* Через 180-й меридиан прямоугольник НЕ переносится: у нас нет данных по обе
|
|
91
|
+
* стороны океана, а поддержка переноса тянет за собой особый случай в каждом
|
|
92
|
+
* методе. Если понадобится — добавлять его надо вместе с тестами на склейку.
|
|
93
|
+
*/
|
|
94
|
+
/**
|
|
95
|
+
* Рамка любым из видов MapLibre: `LngLatBounds`, пара углов `[юго-запад, северо-восток]` или `[запад, юг, восток, север]`
|
|
96
|
+
* (02.11.2026).
|
|
97
|
+
*/
|
|
98
|
+
type LngLatBoundsLike = LngLatBounds | readonly [LngLatLike, LngLatLike] | readonly [number, number, number, number];
|
|
99
|
+
declare class LngLatBounds {
|
|
100
|
+
west: number;
|
|
101
|
+
south: number;
|
|
102
|
+
east: number;
|
|
103
|
+
north: number;
|
|
104
|
+
constructor(sw?: LngLatLike, ne?: LngLatLike);
|
|
105
|
+
/** Рамка по набору точек. Пустой набор даёт пустую рамку, а не ошибку. */
|
|
106
|
+
/** Рамка из любого вида `LngLatBoundsLike`; `LngLatBounds` возвращается как есть. */
|
|
107
|
+
static convert(input: LngLatBoundsLike): LngLatBounds;
|
|
108
|
+
static from(points: Iterable<LngLatLike>): LngLatBounds;
|
|
109
|
+
extend(point: LngLatLike | LngLatBounds): this;
|
|
110
|
+
isEmpty(): boolean;
|
|
111
|
+
getCenter(): LngLat;
|
|
112
|
+
getWest(): number;
|
|
113
|
+
getSouth(): number;
|
|
114
|
+
getEast(): number;
|
|
115
|
+
getNorth(): number;
|
|
116
|
+
getNorthWest(): LngLat;
|
|
117
|
+
getSouthEast(): LngLat;
|
|
118
|
+
/** `[[запад, юг], [восток, север]]`, как `toArray` MapLibre. */
|
|
119
|
+
toArray(): [[number, number], [number, number]];
|
|
120
|
+
getSouthWest(): LngLat;
|
|
121
|
+
getNorthEast(): LngLat;
|
|
122
|
+
contains(point: LngLatLike): boolean;
|
|
123
|
+
/** Расширить на долю своего размера — «немного воздуха» вокруг объекта. */
|
|
124
|
+
pad(fraction: number): this;
|
|
125
|
+
/** Углы в нормализованном меркаторе — в этих единицах и считается вписывание. */
|
|
126
|
+
toMercator(): {
|
|
127
|
+
minX: number;
|
|
128
|
+
minY: number;
|
|
129
|
+
maxX: number;
|
|
130
|
+
maxY: number;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Размер экрана, поворот и поля — всё, что нужно, чтобы вписать рамку. */
|
|
134
|
+
interface FitViewport {
|
|
135
|
+
width: number;
|
|
136
|
+
height: number;
|
|
137
|
+
bearing?: number;
|
|
138
|
+
padding?: {
|
|
139
|
+
top?: number;
|
|
140
|
+
right?: number;
|
|
141
|
+
bottom?: number;
|
|
142
|
+
left?: number;
|
|
143
|
+
};
|
|
144
|
+
maxZoom?: number;
|
|
145
|
+
minZoom?: number;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Камера, при которой рамка видна целиком.
|
|
149
|
+
*
|
|
150
|
+
* Считается ЧИСТОЙ функцией, отдельно от карты: так её можно проверить без
|
|
151
|
+
* браузера — а «влезло ровно» или «влезло с запасом в полтора зума» на
|
|
152
|
+
* скриншоте всё равно не различить.
|
|
153
|
+
*
|
|
154
|
+
* Два неочевидных места:
|
|
155
|
+
* • Рамка вписывается в ПОВЁРНУТОЙ системе. При развороте карты тот же
|
|
156
|
+
* прямоугольник занимает другую часть экрана, и вписывание по осям меркатора
|
|
157
|
+
* срезало бы углы.
|
|
158
|
+
* • Поля — это не «отступ внутрь», а занятое интерфейсом место. Поэтому центр
|
|
159
|
+
* карты уезжает на половину разницы полей: рамка встаёт в середину
|
|
160
|
+
* СВОБОДНОЙ области, а не экрана.
|
|
161
|
+
*/
|
|
162
|
+
declare function cameraForBounds(bounds: LngLatBounds, view: FitViewport): {
|
|
163
|
+
center: LngLat;
|
|
164
|
+
zoom: number;
|
|
165
|
+
bearing: number;
|
|
166
|
+
} | null;
|
|
167
|
+
|
|
168
|
+
interface SpeedLimit {
|
|
169
|
+
kmh: number;
|
|
170
|
+
source: 'osm' | 'class';
|
|
171
|
+
cls?: string;
|
|
172
|
+
urban?: boolean;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Разбор Mapbox Vector Tile (spec 2.1) — наш тайлсервер отдаёт именно его
|
|
177
|
+
* (схема OpenMapTiles v3: building / transportation / water / landuse / poi …).
|
|
178
|
+
*
|
|
179
|
+
* Читаем «лениво»: сначала только оглавление слоёв, геометрию каждой фичи
|
|
180
|
+
* распаковываем по требованию. На тайл с 20 тыс. фич это разница между
|
|
181
|
+
* 40 мс и 3 мс, когда генератору нужен один слой из пятнадцати.
|
|
182
|
+
*/
|
|
183
|
+
declare const enum GeomType {
|
|
184
|
+
Unknown = 0,
|
|
185
|
+
Point = 1,
|
|
186
|
+
LineString = 2,
|
|
187
|
+
Polygon = 3
|
|
188
|
+
}
|
|
189
|
+
type PropValue = string | number | boolean | null;
|
|
190
|
+
/** Кольцо/линия: плоский массив [x0,y0,x1,y1,...] в координатах тайла [0..extent]. */
|
|
191
|
+
type Ring = number[];
|
|
192
|
+
declare class VectorTileFeature {
|
|
193
|
+
private pbf;
|
|
194
|
+
readonly keys: string[];
|
|
195
|
+
readonly values: PropValue[];
|
|
196
|
+
readonly extent: number;
|
|
197
|
+
id?: number;
|
|
198
|
+
type: GeomType;
|
|
199
|
+
properties: Record<string, PropValue>;
|
|
200
|
+
/** Позиция блока геометрии в буфере; -1 — геометрии нет. Пишется читателем полей. */
|
|
201
|
+
geomOffset: number;
|
|
202
|
+
constructor(pbf: Pbf, keys: string[], values: PropValue[], extent: number);
|
|
203
|
+
static read(pbf: Pbf, end: number, keys: string[], values: PropValue[], extent: number): VectorTileFeature;
|
|
204
|
+
/** Кольца/линии фичи. Для полигонов внешние и внутренние идут вперемешку — см. splitPolygons. */
|
|
205
|
+
loadGeometry(): Ring[];
|
|
206
|
+
/** BBox фичи в координатах тайла — дешёвый отсев до триангуляции. */
|
|
207
|
+
bbox(): [number, number, number, number];
|
|
208
|
+
}
|
|
209
|
+
declare class VectorTileLayer {
|
|
210
|
+
private pbf;
|
|
211
|
+
version: number;
|
|
212
|
+
name: string;
|
|
213
|
+
extent: number;
|
|
214
|
+
readonly featureOffsets: number[];
|
|
215
|
+
readonly keys: string[];
|
|
216
|
+
readonly values: PropValue[];
|
|
217
|
+
constructor(pbf: Pbf);
|
|
218
|
+
static read(pbf: Pbf, end: number): VectorTileLayer;
|
|
219
|
+
get length(): number;
|
|
220
|
+
feature(i: number): VectorTileFeature;
|
|
221
|
+
/** Итератор по всем фичам слоя. */
|
|
222
|
+
features(): Generator<VectorTileFeature>;
|
|
223
|
+
}
|
|
224
|
+
declare class VectorTile {
|
|
225
|
+
readonly layers: Record<string, VectorTileLayer>;
|
|
226
|
+
constructor(buffer: ArrayBuffer | Uint8Array);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Разбивает кольца полигона на группы «внешнее + его дырки».
|
|
230
|
+
* Ориентация по знаку площади: в MVT внешние кольца по часовой (положительная
|
|
231
|
+
* площадь в системе с Y вниз), дырки — против.
|
|
232
|
+
*/
|
|
233
|
+
declare function splitPolygons(rings: Ring[]): {
|
|
234
|
+
outer: Ring;
|
|
235
|
+
holes: Ring[];
|
|
236
|
+
}[];
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* ОГРАНИЧЕНИЕ СКОРОСТИ ПО ИНДЕКСУ ТАЙЛА — источник правды для портов (`SpeedLimits.kt`, `SpeedLimitIndex.swift`)
|
|
240
|
+
* и натива (`native/src/navigram/speed_limit.cpp`, откуда логика и пришла, 17.10.2026).
|
|
241
|
+
*
|
|
242
|
+
* Зачем. Навигатор спрашивал знак раз в 0.9 с запросом по НАРИСОВАННОМУ: `project` + до четырёх
|
|
243
|
+
* `queryRenderedFeatures` (дорога точкой с допуском 3, 7, 12 px и застройка в 12 px) в потоке карты перед кадром.
|
|
244
|
+
* Перебор слоёв стиля и всех треугольников домов тайла под машиной — 18 мс на Redmi Note 11, провал кадра «раз в
|
|
245
|
+
* 0.9 с» (PLAN N6). Здесь сырой тайл основы ОДИН раз разбирается в индекс по слоям тайла: отрезки `transportation`
|
|
246
|
+
* сеткой 32² и признаки застройки (`landuse` городских классов — многоугольниками, `building`/`housenumber`/`poi` —
|
|
247
|
+
* битовой сеткой присутствия 256²). Ответ по готовому индексу — микросекунды. Где собирать индекс (воркер, пул,
|
|
248
|
+
* очередь) — решает платформа: сборка чистая, на входе байты, на выходе неизменяемый индекс.
|
|
249
|
+
*
|
|
250
|
+
* ★ Отличие от запроса по нарисованному — осознанное: дорога — БЛИЖАЙШАЯ проезжая в пределах 12 px (а не верхняя
|
|
251
|
+
* по порядку отрисовки среди попавших в 3/7/12 px), застройка — дом/номер дома/POI в радиусе 12 px или городской
|
|
252
|
+
* `landuse` под точкой. Запрос по нарисованному домов и подписей рядом с осью дороги почти не находил (заливка
|
|
253
|
+
* ловится попаданием центра, символы не ловятся вовсе), и «в городе ли» решал фактически один `landuse`.
|
|
254
|
+
* Сверка со старым ответом — `scripts/speed-index-vs-query.mjs`, цифры — в `native/PLAN.md`.
|
|
255
|
+
*
|
|
256
|
+
* Решение по найденному — та же чистая часть `speedLimitFromFeatures`: дорога одной фичей `transportation`,
|
|
257
|
+
* застройка — одной фичей `building` (её слой и есть признак, свойства не читаются).
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
/** Название улицы: местное, русское (если есть) и номер дороги (`M41`). */
|
|
261
|
+
interface RoadName {
|
|
262
|
+
name: string;
|
|
263
|
+
nameRu: string | null;
|
|
264
|
+
ref: string | null;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
type Mat4 = Float64Array;
|
|
268
|
+
type Vec3 = [number, number, number];
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Идентификатор тайла. wrap — номер копии мира по X (карта повторяется при панораме
|
|
272
|
+
* через антимеридиан): данные у копий одни и те же, а матрица разная, поэтому
|
|
273
|
+
* ключ кеша данных (dataKey) и ключ отрисовки (key) — разные вещи.
|
|
274
|
+
*/
|
|
275
|
+
declare class TileID {
|
|
276
|
+
readonly z: number;
|
|
277
|
+
readonly x: number;
|
|
278
|
+
readonly y: number;
|
|
279
|
+
readonly wrap: number;
|
|
280
|
+
private dataKeyOrNull;
|
|
281
|
+
private keyOrNull;
|
|
282
|
+
constructor(z: number, x: number, y: number, wrap?: number);
|
|
283
|
+
get dataKey(): string;
|
|
284
|
+
get key(): string;
|
|
285
|
+
parent(): TileID | null;
|
|
286
|
+
children(): TileID[];
|
|
287
|
+
/** Предок на заданном зуме (или сам тайл). */
|
|
288
|
+
scaledTo(z: number): TileID;
|
|
289
|
+
isAncestorOf(other: TileID): boolean;
|
|
290
|
+
/** Границы тайла в нормализованном меркаторе, с учётом копии мира. */
|
|
291
|
+
bounds(): {
|
|
292
|
+
minX: number;
|
|
293
|
+
minY: number;
|
|
294
|
+
maxX: number;
|
|
295
|
+
maxY: number;
|
|
296
|
+
};
|
|
297
|
+
toString(): string;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Глобус.
|
|
302
|
+
*
|
|
303
|
+
* Устроен так же, как у Mapbox: тайлы остаются ОБЫЧНЫМИ меркаторными, а на сферу
|
|
304
|
+
* их натягивает вершинный шейдер. Переписывать конвейер данных не пришлось —
|
|
305
|
+
* поменялось только то, как вершина попадает из тайла в пространство камеры.
|
|
306
|
+
*
|
|
307
|
+
* Ключевое решение, которое позволило не трогать камеру вовсе: глобус даёт не
|
|
308
|
+
* своё пространство, а **локальные координаты в касательной плоскости центра
|
|
309
|
+
* карты** — x на восток, y на юг, z вверх, начало в точке под камерой. Ровно то
|
|
310
|
+
* же, что даёт плоская карта. Поэтому:
|
|
311
|
+
*
|
|
312
|
+
* - вся существующая камера (наклон, поворот, перспектива, пирамида видимости)
|
|
313
|
+
* работает без единой правки;
|
|
314
|
+
* - переход «глобус → плоская карта» это обычный `mix` двух позиций в ОДНОМ
|
|
315
|
+
* пространстве, а не сшивка разных проекций. В центре кадра они совпадают
|
|
316
|
+
* тождественно, поэтому шва там нет по построению.
|
|
317
|
+
*
|
|
318
|
+
* Ориентация осей повторяет меркатор: y растёт на ЮГ (`-sin(lat)`), как и в
|
|
319
|
+
* наших мировых пикселях. Иначе на переходе карта переворачивалась бы.
|
|
320
|
+
*/
|
|
321
|
+
/**
|
|
322
|
+
* Потолок наклона на глобусе. Столько же по умолчанию у Mapbox: выше камера
|
|
323
|
+
* заваливается за горизонт шара, и смотреть становится не на что.
|
|
324
|
+
*/
|
|
325
|
+
declare const GLOBE_MAX_PITCH = 60;
|
|
326
|
+
/** Зумы, на которых происходит переход. Ниже — сфера, выше — плоскость. */
|
|
327
|
+
declare const GLOBE_ZOOM_MIN = 4.5;
|
|
328
|
+
declare const GLOBE_ZOOM_MAX = 6;
|
|
329
|
+
/**
|
|
330
|
+
* Радиус сферы в мировых пикселях.
|
|
331
|
+
*
|
|
332
|
+
* Берём так, чтобы длина экватора совпала с шириной мира меркатора: тогда на
|
|
333
|
+
* экваторе масштабы глобуса и плоской карты равны, и переход не «дышит».
|
|
334
|
+
* Mapbox согласует масштаб на широте 45°, но у нас минимальный зум не такой
|
|
335
|
+
* мелкий, и экватор нагляднее.
|
|
336
|
+
*/
|
|
337
|
+
declare const globeRadius: (worldSize: number) => number;
|
|
338
|
+
/**
|
|
339
|
+
* Доля плоской карты в смеси: 0 — чистая сфера, 1 — чистый меркатор.
|
|
340
|
+
* Между порогами интерполируется гладко, иначе переход виден скачком.
|
|
341
|
+
*/
|
|
342
|
+
declare function globeFlatMix(zoom: number): number;
|
|
343
|
+
/** Единичный вектор направления на точку. Y на юг — как в меркаторе. */
|
|
344
|
+
declare function lngLatToUnit(lng: number, lat: number): Vec3;
|
|
345
|
+
declare function unitToLngLat(v: Vec3): {
|
|
346
|
+
lng: number;
|
|
347
|
+
lat: number;
|
|
348
|
+
};
|
|
349
|
+
interface GlobeBasis {
|
|
350
|
+
/** Восток, юг, вверх в точке центра карты — колонки перехода в локальные координаты. */
|
|
351
|
+
east: Vec3;
|
|
352
|
+
south: Vec3;
|
|
353
|
+
up: Vec3;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Касательный базис в точке центра карты.
|
|
357
|
+
*
|
|
358
|
+
* Порядок осей (восток, юг, вверх) совпадает с нашими мировыми пикселями, где
|
|
359
|
+
* y направлен вниз/на юг. Система при этом левая — та же, что у тайлов, поэтому
|
|
360
|
+
* намотка полигонов и отсечение граней остаются прежними.
|
|
361
|
+
*/
|
|
362
|
+
declare function globeBasis(lng: number, lat: number): GlobeBasis;
|
|
363
|
+
/**
|
|
364
|
+
* Точка сферы → локальные координаты касательной плоскости центра.
|
|
365
|
+
* Ровно та же формула, что в вершинном шейдере, — держать их согласованными
|
|
366
|
+
* обязательно, иначе CPU и GPU разойдутся в размещении подписей.
|
|
367
|
+
*/
|
|
368
|
+
declare function globeToLocal(unit: Vec3, radius: number, basis: GlobeBasis): Vec3;
|
|
369
|
+
/**
|
|
370
|
+
* Пересечение луча со сферой — обратная проекция на глобусе.
|
|
371
|
+
* Возвращает БЛИЖНЮЮ точку или null, если луч прошёл мимо.
|
|
372
|
+
*/
|
|
373
|
+
declare function raySphere(origin: Vec3, dir: Vec3, radius: number): Vec3 | null;
|
|
374
|
+
|
|
375
|
+
type Projection = 'mercator' | 'globe';
|
|
376
|
+
interface ScreenPoint$1 {
|
|
377
|
+
x: number;
|
|
378
|
+
y: number;
|
|
379
|
+
}
|
|
380
|
+
/** Экранная точка объектом или массивом `[x, y]` — как `PointLike` MapLibre (02.11.2026). */
|
|
381
|
+
type PointLike = ScreenPoint$1 | readonly [number, number];
|
|
382
|
+
/** `PointLike` → `{ x, y }`. */
|
|
383
|
+
declare function toPoint(p: PointLike): ScreenPoint$1;
|
|
384
|
+
/**
|
|
385
|
+
* Состояние камеры и все производные матрицы.
|
|
386
|
+
*
|
|
387
|
+
* Пространства координат:
|
|
388
|
+
* - «мировые пиксели» (px): нормализованный меркатор · worldSize(zoom), Y вниз;
|
|
389
|
+
* - пространство рендера: то же по X/Y, но Z в МЕТРАХ (матрица сама домножает на
|
|
390
|
+
* pixelsPerMeter). Так вершины зданий несут честную высоту и не зависят от зума.
|
|
391
|
+
*
|
|
392
|
+
* Отсюда две матрицы: viewProjPx (отсечение, LOD, расстояния — всё в пикселях)
|
|
393
|
+
* и projMatrix (рендер, Z в метрах). Их легко перепутать — единицы Z разные.
|
|
394
|
+
*/
|
|
395
|
+
/**
|
|
396
|
+
* Ближе этого (метры) дальняя плоскость камеры и кромка тумана не встают — на крупном зуме дорога видна
|
|
397
|
+
* хотя бы на километр. Чуть дальше стены дымки (`FOG_FAR_MIN_M` = 900 м, `layers/fog`), чтобы обрыв
|
|
398
|
+
* геометрии прятался в уже сплошной дымке.
|
|
399
|
+
*/
|
|
400
|
+
declare const FOG_CUTOFF_MIN_M = 1000;
|
|
401
|
+
/**
|
|
402
|
+
* НАКЛОН ПО ВЫСОТЕ КАМЕРЫ — как у Apple Maps: наклонная 3D-карта бывает только у земли.
|
|
403
|
+
*
|
|
404
|
+
* Отдалились — карта сама выпрямляется (с z13 и выше — в 2D), приблизились — наклон возвращается к
|
|
405
|
+
* тому, что просил пользователь (`Transform.wantedPitch`). Отсюда же поведение тумана, как у Apple:
|
|
406
|
+
* он виден только с горизонтом в кадре, а горизонт виден только вблизи. И отсюда экономия: на мелком
|
|
407
|
+
* зуме наклон 75° открывал до горизонта всю область вокруг — сотни тайлов, которые прятал туман.
|
|
408
|
+
*
|
|
409
|
+
* Узлы — зум и предел наклона, между ними линейно; ниже первого — предел первого, с последнего зума
|
|
410
|
+
* предела нет (только `maxPitch`). Похоже устроено у Google Maps (до z10 — 30°, к z14 — 45°, выше —
|
|
411
|
+
* больше) и у MapKit (наклон ограничен высотой камеры).
|
|
412
|
+
*/
|
|
413
|
+
declare const PITCH_BY_ZOOM: ReadonlyArray<readonly [number, number]>;
|
|
414
|
+
/** Предел наклона на зуме по узлам `PITCH_BY_ZOOM`; `Infinity` — с последнего узла предела нет. */
|
|
415
|
+
declare function pitchLimitAt(zoom: number, stops?: ReadonlyArray<readonly [number, number]>): number;
|
|
416
|
+
declare class Transform {
|
|
417
|
+
width: number;
|
|
418
|
+
height: number;
|
|
419
|
+
minZoom: number;
|
|
420
|
+
maxZoom: number;
|
|
421
|
+
/**
|
|
422
|
+
* Рамка, за которую не выпускается ЦЕНТР карты. `null` — ограничения нет.
|
|
423
|
+
*
|
|
424
|
+
* Прижимается в сеттере центра, а не при отрисовке: центр ставят и жесты, и анимация, и
|
|
425
|
+
* приложение, и проверить это в одном месте — единственный способ не забыть ни одного из них.
|
|
426
|
+
*/
|
|
427
|
+
maxBounds: LngLatBounds | null;
|
|
428
|
+
/**
|
|
429
|
+
* Повторять ли мир по горизонтали при отъезде.
|
|
430
|
+
*
|
|
431
|
+
* На мелком зуме в кадр помещается больше одного оборота Земли, и копии закрывают пустоту по
|
|
432
|
+
* краям. Приложению это иногда мешает — например, когда по карте водят выделение и вторая копия
|
|
433
|
+
* ловит тот же клик, — поэтому повтор выключается (`map.setRenderWorldCopies`).
|
|
434
|
+
*/
|
|
435
|
+
renderWorldCopies: boolean;
|
|
436
|
+
minPitch: number;
|
|
437
|
+
maxPitch: number;
|
|
438
|
+
private _fogCutoff;
|
|
439
|
+
/**
|
|
440
|
+
* ДАЛЬНОСТЬ ОТСЕЧЕНИЯ ТУМАНА (`fog` стиля): глубина по оси взгляда в расстояниях до центра кадра.
|
|
441
|
+
*
|
|
442
|
+
* Становится ДАЛЬНЕЙ ПЛОСКОСТЬЮ камеры: за ней GPU не рисует ничего, а отбор тайлов (та же пирамида
|
|
443
|
+
* видимости в `isTileVisible`) их не выбирает и не грузит — как и 3D-модели (`isSphereVisible`).
|
|
444
|
+
* Туман в шейдере меряет ту же глубину, поэтому на кромке он уже сплошной. `Infinity` — не режем.
|
|
445
|
+
*/
|
|
446
|
+
get fogCutoff(): number;
|
|
447
|
+
/**
|
|
448
|
+
* Дальняя плоскость тумана в мировых пикселях по оси взгляда: `fogCutoff` в долях расстояния до
|
|
449
|
+
* центра, но НЕ БЛИЖЕ `FOG_CUTOFF_MIN_M` метров. Доли на крупном зуме — десятки метров (z22: ~32 м), и
|
|
450
|
+
* камера обрезала дорогу прямо перед собой. `Infinity` — не режем.
|
|
451
|
+
*/
|
|
452
|
+
fogCutoffDepth(): number;
|
|
453
|
+
set fogCutoff(k: number);
|
|
454
|
+
/**
|
|
455
|
+
* КРЕН камеры, градусы: поворот вокруг оси взгляда.
|
|
456
|
+
*
|
|
457
|
+
* Наклон (`pitch`) кладёт камеру вперёд, поворот (`bearing`) вращает карту под ней, а крен
|
|
458
|
+
* заваливает сам кадр — как накренившийся самолёт. Нужен полётам и панорамам; на обычной карте
|
|
459
|
+
* остаётся нулём. Порядок сборки тот же, что у MapLibre: крен идёт МЕЖДУ отъездом камеры и
|
|
460
|
+
* наклоном, иначе он начал бы вращать не кадр, а землю под ним.
|
|
461
|
+
*
|
|
462
|
+
* Свойство, а не поле: присваивание обязано пометить камеру грязной, иначе матрицы останутся
|
|
463
|
+
* прежними и крен не доедет до кадра.
|
|
464
|
+
*/
|
|
465
|
+
private _roll;
|
|
466
|
+
private _center;
|
|
467
|
+
/**
|
|
468
|
+
* ВЫСОТА ЗЕМЛИ ПОД ЦЕНТРОМ КАРТЫ, метры. Ставится рельефом каждый кадр; без рельефа — ноль.
|
|
469
|
+
*
|
|
470
|
+
* Камера у нас стоит на фиксированном расстоянии от ТОЧКИ ЦЕНТРА, а точка эта лежала на нулевой
|
|
471
|
+
* высоте. Над горой в 2 км это значит, что камера оказывается внутри горы: земля поднялась, а
|
|
472
|
+
* она — нет. Поднимаем всю связку камера-центр на высоту земли — ровно так же поступает MapLibre
|
|
473
|
+
* (`transform.elevation`), и по той же причине: иначе рельеф нельзя даже осмотреть.
|
|
474
|
+
*/
|
|
475
|
+
private _centerElevation;
|
|
476
|
+
private _zoom;
|
|
477
|
+
private _bearing;
|
|
478
|
+
private _pitch;
|
|
479
|
+
/** Наклон, который просили (`pitch =`); на экране — он же, урезанный пределом по зуму. */
|
|
480
|
+
private _wantedPitch;
|
|
481
|
+
/** Предел наклона по зуму. У голой математики камеры выключен; карта включает его опцией `pitchByZoom`. */
|
|
482
|
+
private _pitchByZoom;
|
|
483
|
+
private _fov;
|
|
484
|
+
private _worldSize;
|
|
485
|
+
private _pixelsPerMeter;
|
|
486
|
+
private _cameraToCenterDistance;
|
|
487
|
+
private _centerX;
|
|
488
|
+
private _centerY;
|
|
489
|
+
private _projMatrix;
|
|
490
|
+
/** Элемент [14] перспективы: z клипа = A·z + B (см. `projZOffset`). */
|
|
491
|
+
private _projZ;
|
|
492
|
+
private _viewProjPx;
|
|
493
|
+
private _viewMatrix;
|
|
494
|
+
private _pixelMatrix;
|
|
495
|
+
private _pixelMatrixInverse;
|
|
496
|
+
private _cameraPosPx;
|
|
497
|
+
private _frustumPlanes;
|
|
498
|
+
private _dirty;
|
|
499
|
+
/**
|
|
500
|
+
* Проекция. `globe` действует только до GLOBE_ZOOM_MAX — выше карта всё равно
|
|
501
|
+
* плоская, и держать сферу там значило бы платить за неё зря.
|
|
502
|
+
*/
|
|
503
|
+
projection: Projection;
|
|
504
|
+
/**
|
|
505
|
+
* ЗУМЫ ПЕРЕХОДА ШАР → ПЛОСКОСТЬ ИЗ СТИЛЯ (этап y, `porting/unified-style-format.md` §15): `projection.type`
|
|
506
|
+
* MapLibre по зуму (`["interpolate", …, ["zoom"], z0, "vertical-perspective", z1, "mercator"]`, сахар
|
|
507
|
+
* `globe` — z11 → z12). Доля плоскости между ними — кривой `interpolate` (у MapLibre — линейная смесь
|
|
508
|
+
* положений, `GlobeProjection.transitionState`); `max: Infinity` — шар на любом зуме (`vertical-perspective`).
|
|
509
|
+
* `null` — свои зумы глобуса (`GLOBE_ZOOM_MIN`–`GLOBE_ZOOM_MAX`, гладкая ступенька).
|
|
510
|
+
*/
|
|
511
|
+
globeZooms: {
|
|
512
|
+
min: number;
|
|
513
|
+
max: number;
|
|
514
|
+
base?: number;
|
|
515
|
+
} | null;
|
|
516
|
+
/** Зум, с которого шар уже не нужен. */
|
|
517
|
+
private get globeTop();
|
|
518
|
+
/** Доля плоской карты на зуме: из стиля — кривой `interpolate`, иначе своя гладкая ступенька. */
|
|
519
|
+
private flatMixAt;
|
|
520
|
+
private _f32;
|
|
521
|
+
private _tileMatrix;
|
|
522
|
+
private _localView;
|
|
523
|
+
private _localProj;
|
|
524
|
+
private _localPixel;
|
|
525
|
+
private _localPixelInverse;
|
|
526
|
+
private _localF32;
|
|
527
|
+
private _globeBasis;
|
|
528
|
+
private _objectF32;
|
|
529
|
+
private _objectMatrix;
|
|
530
|
+
private _shadowView;
|
|
531
|
+
private _shadowProj;
|
|
532
|
+
private _shadowVP;
|
|
533
|
+
/** То же, но принимает высоту в метрах — как projMatrix. */
|
|
534
|
+
private _shadowVPm;
|
|
535
|
+
private _shadowTile;
|
|
536
|
+
private _shadowObject;
|
|
537
|
+
private _shadowTile32;
|
|
538
|
+
private _shadowObject32;
|
|
539
|
+
private _shadowValid;
|
|
540
|
+
constructor();
|
|
541
|
+
get center(): LngLat;
|
|
542
|
+
set center(v: LngLat);
|
|
543
|
+
/** Высота земли под центром, метры (ставит рельеф). */
|
|
544
|
+
get centerElevation(): number;
|
|
545
|
+
set centerElevation(v: number);
|
|
546
|
+
/**
|
|
547
|
+
* Нижняя граница зума на глобусе: дальше шар становится точкой в углу экрана.
|
|
548
|
+
*
|
|
549
|
+
* Считается от размера кадра, а не числом: радиус сферы в мировых пикселях
|
|
550
|
+
* растёт с зумом, и «достаточно крупно» — это доля меньшей стороны экрана.
|
|
551
|
+
*/
|
|
552
|
+
globeMinZoom(): number;
|
|
553
|
+
/** Нижняя граница зума с учётом проекции. */
|
|
554
|
+
effectiveMinZoom(): number;
|
|
555
|
+
get zoom(): number;
|
|
556
|
+
set zoom(z: number);
|
|
557
|
+
get bearing(): number;
|
|
558
|
+
set bearing(b: number);
|
|
559
|
+
get pitch(): number;
|
|
560
|
+
set pitch(p: number);
|
|
561
|
+
/** Наклон, который просили; на экране может быть меньше — по пределу зума (`pitchByZoom`). */
|
|
562
|
+
get wantedPitch(): number;
|
|
563
|
+
/**
|
|
564
|
+
* Наклон по высоте камеры (`PITCH_BY_ZOOM`). У карты по умолчанию включён (`MapOptions.pitchByZoom`).
|
|
565
|
+
* Выключают его те, кто ставит камеру сам и знает, зачем: ведение навигатора держит свой наклон.
|
|
566
|
+
*/
|
|
567
|
+
get pitchByZoom(): boolean;
|
|
568
|
+
set pitchByZoom(on: boolean);
|
|
569
|
+
/** Предел наклона на текущем зуме: `maxPitch`, глобус и высота камеры. */
|
|
570
|
+
pitchLimit(): number;
|
|
571
|
+
private applyPitch;
|
|
572
|
+
/** Вертикальный угол обзора в градусах. */
|
|
573
|
+
get roll(): number;
|
|
574
|
+
set roll(deg: number);
|
|
575
|
+
get fov(): number;
|
|
576
|
+
set fov(deg: number);
|
|
577
|
+
resize(width: number, height: number): void;
|
|
578
|
+
get worldSize(): number;
|
|
579
|
+
get pixelsPerMeter(): number;
|
|
580
|
+
get cameraToCenterDistance(): number;
|
|
581
|
+
get cameraPositionPx(): [number, number, number];
|
|
582
|
+
/**
|
|
583
|
+
* Свободный член глубины перспективы (B в z клипа = A·z + B).
|
|
584
|
+
*
|
|
585
|
+
* Нужен, чтобы сдвинуть глубину точки к камере, не сдвигая её на экране: приблизить точку на долю
|
|
586
|
+
* `k` её расстояния — то же самое, что прибавить к z клипа `B·k/(1−k)`, одну постоянную на кадр
|
|
587
|
+
* (см. `LineLayerSpec.depthTest`).
|
|
588
|
+
*/
|
|
589
|
+
get projZOffset(): number;
|
|
590
|
+
get projMatrix(): Mat4;
|
|
591
|
+
/** Мировые пиксели → экран в однородных координатах (x, y, z, w; делить на w). */
|
|
592
|
+
get pixelMatrix(): Mat4;
|
|
593
|
+
get viewMatrix(): Mat4;
|
|
594
|
+
/** Центр карты в мировых пикселях. */
|
|
595
|
+
get centerPointPx(): {
|
|
596
|
+
x: number;
|
|
597
|
+
y: number;
|
|
598
|
+
};
|
|
599
|
+
clone(): Transform;
|
|
600
|
+
/** Географическая точка (+ высота в метрах) → пиксели экрана. */
|
|
601
|
+
project(lngLat: LngLat, altitudeMeters?: number): ScreenPoint$1;
|
|
602
|
+
/**
|
|
603
|
+
* Мировые пиксели → экран. null, если точка за камерой: при наклоне 70°
|
|
604
|
+
* половина мира оказывается позади, и без этой проверки подписи «отражаются»
|
|
605
|
+
* в верхнюю часть экрана.
|
|
606
|
+
*/
|
|
607
|
+
worldPxToPoint(wx: number, wy: number, altitudeMeters?: number): ScreenPoint$1 | null;
|
|
608
|
+
/** Пиксели экрана → география на уровне земли (луч сквозь плоскость z=0). */
|
|
609
|
+
unproject(point: ScreenPoint$1): LngLat;
|
|
610
|
+
/**
|
|
611
|
+
* ВЫСОТА ЗЕМЛИ В ТОЧКЕ, метры — её ставит рельеф.
|
|
612
|
+
*
|
|
613
|
+
* Без неё обратный перевод «экран → место» считает землю плоскостью на нуле. На рельефе земля
|
|
614
|
+
* лежит на своей высоте, и на городском зуме при наклоне промах доходит до полутора километров:
|
|
615
|
+
* клик по дому открывал карточку соседнего квартала, а перетаскивание карты уезжало из-под
|
|
616
|
+
* пальца. Ровно это же (и ровно так же, итерациями) делает MapLibre в `pointCoordinate3D`.
|
|
617
|
+
*/
|
|
618
|
+
elevationAt: ((mx: number, my: number) => number) | null;
|
|
619
|
+
/** Пиксели экрана → мировые пиксели на плоскости земли. */
|
|
620
|
+
pointToWorldPx(point: ScreenPoint$1): {
|
|
621
|
+
x: number;
|
|
622
|
+
y: number;
|
|
623
|
+
};
|
|
624
|
+
/** Сдвигает центр так, чтобы координата lngLat оказалась под точкой экрана. */
|
|
625
|
+
setLocationAtPoint(lngLat: LngLat, point: ScreenPoint$1): void;
|
|
626
|
+
/**
|
|
627
|
+
* Центр, посчитанный жестом или инерцией (минуя сеттер, без рамки `maxBounds` — её держит карта). Точка экрана
|
|
628
|
+
* за горизонтом или нечисловое касание дают NaN — такой шаг пропускается, как и в сеттере.
|
|
629
|
+
*/
|
|
630
|
+
private placeCenter;
|
|
631
|
+
/**
|
|
632
|
+
* Сдвигает карту на (dx, dy) пикселей экрана В МАСШТАБЕ ЦЕНТРА: содержимое у центра уезжает ровно на
|
|
633
|
+
* столько же.
|
|
634
|
+
*
|
|
635
|
+
* Нужен инерции броска. Сдвиг здесь ЛИНЕЕН по дельте (пиксель центра переводится в мировые пиксели
|
|
636
|
+
* один раз, разностью по полпикселя в обе стороны), поэтому сумма шагов равна одному большому шагу
|
|
637
|
+
* — путь броска не зависит от частоты кадров, в том числе при наклоне. `setLocationAtPoint` вокруг
|
|
638
|
+
* центра этого не даёт: при перспективе он нелинеен, и десять мелких шагов уводят не туда, куда один
|
|
639
|
+
* крупный. На шаре линейного сдвига нет — там тот же поворот, что у жеста.
|
|
640
|
+
*/
|
|
641
|
+
panByScreenDelta(dx: number, dy: number): void;
|
|
642
|
+
/**
|
|
643
|
+
* Матрица тайла: локальные координаты MVT [0..extent] + высота в метрах → клип.
|
|
644
|
+
* Возвращает переиспользуемый Float32Array — грузить в юниформ сразу, не хранить.
|
|
645
|
+
*/
|
|
646
|
+
tileMatrix(tile: TileID, extent: number): Float32Array;
|
|
647
|
+
/** Та же матрица, но в Float64 — для расчётов на CPU (пикинг, отладка). */
|
|
648
|
+
tileMatrix64(tile: TileID, extent: number, out?: Mat4): Mat4;
|
|
649
|
+
/**
|
|
650
|
+
* Матрица рантайм-объекта: локальные координаты — нормализованный меркатор
|
|
651
|
+
* ОТНОСИТЕЛЬНО origin, Z — метры над землёй.
|
|
652
|
+
*
|
|
653
|
+
* Отличается от тайловой только тем, откуда берётся начало и масштаб: у тайла
|
|
654
|
+
* они продиктованы сеткой, у объекта их выбирает он сам по своей рамке. Смысл
|
|
655
|
+
* переноса тот же — увести из Float32 огромные мировые координаты.
|
|
656
|
+
*/
|
|
657
|
+
objectMatrix(originX: number, originY: number, altitudeMeters?: number): Float32Array;
|
|
658
|
+
/**
|
|
659
|
+
* КВАДРАТ ДРАПИРОВКИ, в который сейчас рисуется плоская карта (15.10.2026). `null` — рисуем на экран.
|
|
660
|
+
*
|
|
661
|
+
* На рельефе плоский проход уходит в текстуры тайлов рельефа (`Renderer.drapeTerrain`), и всё, что в
|
|
662
|
+
* нём рисуется, обязано класть себя в КВАДРАТ ТАЙЛА, а не в кадр. Слои стиля так и делают (матрица
|
|
663
|
+
* тайла), а свои слои приложения и стрелки входов берут матрицу у `objectMatrix` — и получали
|
|
664
|
+
* экранную камеру. Полотно детальных дорог (`ld-pascal-mesh` на вебе, `LdMesh` на Android/iOS)
|
|
665
|
+
* рисовалось в каждую текстуру тайла по проекции кадра и легло на рельеф обрывками тёмных полос
|
|
666
|
+
* поперёк реки (жалоба с navi.gram.tj, Худжанд, z17, наклон 65°). Пока квадрат задан, `objectMatrix`
|
|
667
|
+
* переводит меркатор в квадрат рельефа, а высоту в метрах обнуляет: в текстуре земля плоская, рельеф
|
|
668
|
+
* ей даст решётка.
|
|
669
|
+
*/
|
|
670
|
+
drapeSquare: {
|
|
671
|
+
z: number;
|
|
672
|
+
x: number;
|
|
673
|
+
y: number;
|
|
674
|
+
} | null;
|
|
675
|
+
/**
|
|
676
|
+
* `objectMatrix` в драпировке: локальный меркатор (от `origin`) → клип квадрата `drapeSquare`.
|
|
677
|
+
*
|
|
678
|
+
* x = 2ⁿ⁺¹·lx + (2ⁿ⁺¹·ox − 2·T.x − 1), y = −2ⁿ⁺¹·ly + (−2ⁿ⁺¹·oy + 2·T.y + 1), z = 0
|
|
679
|
+
*
|
|
680
|
+
* Та же раскладка, что у тайла карты в драпировке (`Renderer.applyTileMatrix`): ось Y перевёрнута, её
|
|
681
|
+
* возвращает шейдер рельефа. Перенос считается в двойной точности — как у обычной `objectMatrix`.
|
|
682
|
+
*/
|
|
683
|
+
private drapeObjectMatrix;
|
|
684
|
+
/**
|
|
685
|
+
* Экранная координата Y линии горизонта (сверху вниз, CSS-пиксели).
|
|
686
|
+
*
|
|
687
|
+
* Крена у нашей камеры нет, поэтому горизонт — всегда ГОРИЗОНТАЛЬНАЯ линия, и
|
|
688
|
+
* небо можно рисовать вертикальным градиентом в экранных координатах. Это и
|
|
689
|
+
* точно, и на порядок дешевле, чем считать направление луча в каждом фрагменте.
|
|
690
|
+
*
|
|
691
|
+
* Значение может быть отрицательным: при малом наклоне горизонт уходит выше
|
|
692
|
+
* кадра, и неба на экране просто нет.
|
|
693
|
+
*/
|
|
694
|
+
horizonScreenY(): number;
|
|
695
|
+
/** Сфера сейчас активна: режим включён и зум ещё не перевалил за переход. */
|
|
696
|
+
get globeActive(): boolean;
|
|
697
|
+
/** Доля плоской карты в смеси: 0 — чистая сфера, 1 — чистый меркатор. */
|
|
698
|
+
get globeFlatMix(): number;
|
|
699
|
+
get globeRadiusPx(): number;
|
|
700
|
+
/**
|
|
701
|
+
* Радиус шара в мировых пикселях. Свой — по экватору (`globeRadius`); у стиля MapLibre (зумы перехода
|
|
702
|
+
* из стиля, этап y) — как у `GlobeTransform` MapLibre: делённый на косинус широты центра, чтобы масштаб
|
|
703
|
+
* в центре кадра совпадал с меркатором и переход шар → плоскость не менял размера карты.
|
|
704
|
+
*/
|
|
705
|
+
private globeRadiusOf;
|
|
706
|
+
get globeBasis(): GlobeBasis;
|
|
707
|
+
/** Та же матрица в Float64 — для расчётов на CPU. */
|
|
708
|
+
get localProjMatrix(): Mat4;
|
|
709
|
+
/**
|
|
710
|
+
* Камера относительно ЦЕНТРА ШАРА, в локальных координатах: направление и
|
|
711
|
+
* косинус угла до горизонта.
|
|
712
|
+
*
|
|
713
|
+
* Считать горизонт от вертикали в центре карты нельзя — это верно только при
|
|
714
|
+
* наклоне 0. При наклоне камера уходит вбок, настоящий горизонт наклоняется
|
|
715
|
+
* вместе с ней, а плоскость, перпендикулярная вертикали, срезает шар по
|
|
716
|
+
* прямой: ровно это и было видно как «часть глобуса скрывается».
|
|
717
|
+
*/
|
|
718
|
+
globeCamera(): {
|
|
719
|
+
dir: Vec3;
|
|
720
|
+
horizonCos: number;
|
|
721
|
+
};
|
|
722
|
+
/**
|
|
723
|
+
* Направления лучей через углы кадра, в локальных координатах.
|
|
724
|
+
*
|
|
725
|
+
* Нужны небу: чтобы посчитать, на каком угловом расстоянии от края планеты
|
|
726
|
+
* находится пиксель, нужен его луч. Считать обратную проекцию в каждом
|
|
727
|
+
* фрагменте дорого и незачем — направления линейны по экрану, поэтому хватает
|
|
728
|
+
* четырёх углов и интерполяции. Так же делает Mapbox (u_frustum_tl/tr/br/bl).
|
|
729
|
+
*
|
|
730
|
+
* Порядок: левый верх, правый верх, левый низ, правый низ.
|
|
731
|
+
*/
|
|
732
|
+
localRayCorners(): Vec3[];
|
|
733
|
+
/**
|
|
734
|
+
* Базис камеры в МИРОВЫХ осях движка (X восток, Y юг, Z вверх) и фокус в пикселях вида.
|
|
735
|
+
*
|
|
736
|
+
* По ним из пикселя восстанавливается луч: dir = normalize(fwd*focal + right*dx + up*dy). Небу
|
|
737
|
+
* этого хватает, чтобы считаться от УГЛА ЛУЧА, а не от экранной высоты, — только так у горизонта
|
|
738
|
+
* получается настоящая воздушная масса, а не нарисованная полоса.
|
|
739
|
+
*/
|
|
740
|
+
cameraRay(): {
|
|
741
|
+
right: Vec3;
|
|
742
|
+
up: Vec3;
|
|
743
|
+
fwd: Vec3;
|
|
744
|
+
focal: number;
|
|
745
|
+
axisElev: number;
|
|
746
|
+
};
|
|
747
|
+
/** Направление на центр планеты и её угловой радиус — для каймы атмосферы. */
|
|
748
|
+
globeDisc(): {
|
|
749
|
+
dir: Vec3;
|
|
750
|
+
angle: number;
|
|
751
|
+
};
|
|
752
|
+
/** Матрица камеры для ЛОКАЛЬНЫХ координат (глобус их и отдаёт). */
|
|
753
|
+
localMatrix(): Float32Array;
|
|
754
|
+
/**
|
|
755
|
+
* Нормализованный меркатор → локальные координаты. Повторяет формулу
|
|
756
|
+
* вершинного шейдера один в один: разойдись они — и подписи, размещаемые на
|
|
757
|
+
* CPU, поедут относительно геометрии.
|
|
758
|
+
*/
|
|
759
|
+
globeLocal(mx: number, my: number): Vec3;
|
|
760
|
+
/** Локальные координаты → экран. null, если точка за камерой. */
|
|
761
|
+
localToPoint(local: Vec3): ScreenPoint$1 | null;
|
|
762
|
+
/**
|
|
763
|
+
* Обратная проекция на сфере: луч из камеры до пересечения с шаром.
|
|
764
|
+
*
|
|
765
|
+
* Центр шара в локальных координатах — (0, 0, −R): начало там, где сфера
|
|
766
|
+
* касается касательной плоскости, а центр на радиус ниже.
|
|
767
|
+
*/
|
|
768
|
+
globeUnproject(point: ScreenPoint$1): LngLat | null;
|
|
769
|
+
/**
|
|
770
|
+
* Видна ли точка сферы: и по горизонту, и по кадру.
|
|
771
|
+
*
|
|
772
|
+
* Горизонт считается от ВЫСОТЫ камеры, а не «передней полусферы»: с конечной
|
|
773
|
+
* высоты видно заметно меньше половины шара, и без этого дальняя сторона
|
|
774
|
+
* рисовалась бы поверх ближней (тест глубины у плоских слоёв выключен).
|
|
775
|
+
*/
|
|
776
|
+
isOnGlobeFront(lng: number, lat: number, slack?: number): boolean;
|
|
777
|
+
/**
|
|
778
|
+
* Пересчитывает матрицы карты теней под текущую камеру.
|
|
779
|
+
*
|
|
780
|
+
* Объём источника подгоняется под ВИДИМУЮ землю, а не задаётся раз и навсегда:
|
|
781
|
+
* при наклоне 70° видимая площадь больше, чем при взгляде сверху, в десятки
|
|
782
|
+
* раз, и фиксированный объём либо обрежет тени спереди, либо размажет их в
|
|
783
|
+
* кашу сзади (весь бюджет текселей уйдёт на пустоту).
|
|
784
|
+
*
|
|
785
|
+
* @param dir куда ЛЕТИТ свет (та же система, что у `u_key_dir`)
|
|
786
|
+
* @param maxHeightMeters потолок сцены: выше него теней не бывает
|
|
787
|
+
*/
|
|
788
|
+
updateShadow(dir: Vec3, maxHeightMeters: number, groundMin?: number, groundMax?: number): void;
|
|
789
|
+
/** Матрицы теней посчитаны и пригодны. */
|
|
790
|
+
get shadowReady(): boolean;
|
|
791
|
+
/**
|
|
792
|
+
* Матрица тени для рантайм-объекта: локальные координаты (нормализованный
|
|
793
|
+
* меркатор относительно origin) → клип источника света.
|
|
794
|
+
*/
|
|
795
|
+
shadowObjectMatrix(originX: number, originY: number, altitudeMeters?: number): Float32Array;
|
|
796
|
+
/** Матрица тайла для прохода глубины: локальные координаты MVT → клип источника. */
|
|
797
|
+
shadowTileMatrix(tile: TileID, extent: number): Float32Array;
|
|
798
|
+
/**
|
|
799
|
+
* Сколько единиц глубины карты теней приходится на МЕТР высоты.
|
|
800
|
+
*
|
|
801
|
+
* Нужно, чтобы задавать смещение против самозатенения в метрах, а не в долях
|
|
802
|
+
* диапазона глубины. Диапазон зависит от объёма источника, а тот — от зума и
|
|
803
|
+
* наклона: одно и то же «0.0015» означало 49 метров на z16 и 15 на z19, и
|
|
804
|
+
* тени обычных домов просто съедались смещением.
|
|
805
|
+
*
|
|
806
|
+
* Матрица источника ортографическая, то есть аффинная, поэтому производная
|
|
807
|
+
* глубины по высоте — это просто её коэффициент при z.
|
|
808
|
+
*/
|
|
809
|
+
shadowDepthPerMeter(): number;
|
|
810
|
+
/** Размер текселя карты теней в мировых пикселях — для наклонного bias. */
|
|
811
|
+
shadowTexelWorldSize(mapSize: number): number;
|
|
812
|
+
/**
|
|
813
|
+
* AABB тайла (мировые пиксели, Z тоже пиксели) против пирамиды видимости.
|
|
814
|
+
* Классический тест «полностью снаружи одной из плоскостей»: даёт ложные
|
|
815
|
+
* попадания на углах, но не теряет видимое — для отбора тайлов этого достаточно.
|
|
816
|
+
*/
|
|
817
|
+
isTileVisible(tile: TileID): boolean;
|
|
818
|
+
/**
|
|
819
|
+
* Видна ли сфера: центр задан в нормализованном меркаторе, высота и радиус — в метрах.
|
|
820
|
+
*
|
|
821
|
+
* Тем же набором плоскостей, что и у тайлов ([[isTileVisible]]). Нужна отсечению 3D-моделей: их
|
|
822
|
+
* отбирают по расстоянию от ЦЕНТРА КАРТЫ, а не по кадру, и при наклонной камере заметная часть
|
|
823
|
+
* радиуса приходится за спину — рисовать её незачем.
|
|
824
|
+
*/
|
|
825
|
+
isSphereVisible(mercX: number, mercY: number, heightM: number, radiusM: number): boolean;
|
|
826
|
+
/**
|
|
827
|
+
* Лежит ли точка ЗА КРОМКОЙ ТУМАНА (`fogCutoff`): её глубина по оси взгляда дальше дальней плоскости.
|
|
828
|
+
* Мировые пиксели по X/Y, высота в метрах. Нужна тому, что рисуется не GPU, — DOM-маркерам.
|
|
829
|
+
*/
|
|
830
|
+
beyondFog(x: number, y: number, altitudeM?: number): boolean;
|
|
831
|
+
/** Расстояние от камеры до ближайшей точки AABB тайла (мировые пиксели). */
|
|
832
|
+
distanceToTile(tile: TileID): number;
|
|
833
|
+
/**
|
|
834
|
+
* Самая дальняя точка земли у НЕНАКЛОНЁННОЙ карты — точка отсчёта для слова «далеко».
|
|
835
|
+
*
|
|
836
|
+
* Смотрим сверху вниз: дальше всех от камеры угол экрана. Всё, что дальше этого, на плоской карте
|
|
837
|
+
* не встречается вовсе и появляется только от наклона.
|
|
838
|
+
*/
|
|
839
|
+
get flatFarDistance(): number;
|
|
840
|
+
/**
|
|
841
|
+
* Зум, на который тайл ТЯНЕТ с такого расстояния.
|
|
842
|
+
*
|
|
843
|
+
* При наклоне карта одним кадром показывает и двор под ногами, и город за несколько километров, а
|
|
844
|
+
* зум у неё один на всех. Дальние тайлы от этого рисуются со всей мелочью ближнего плана: номера
|
|
845
|
+
* домов, тропинки, дворовые проезды — всё то, что на таком расстоянии сливается в грязь, но честно
|
|
846
|
+
* стоит вершин и вызовов отрисовки. Здесь считается, во сколько раз тайл дальше самого дальнего
|
|
847
|
+
* угла плоской карты, и на столько же зум-уровней он «отодвигается»: слой со своим `minzoom` сам
|
|
848
|
+
* пропадёт там, где стал бы неразличим. Ровно это происходит у Mapbox, где дальние тайлы физически
|
|
849
|
+
* берутся с меньшего зума.
|
|
850
|
+
*
|
|
851
|
+
* На ненаклонённой карте не меняет ничего: там дальше отсчётной точки ничего и нет.
|
|
852
|
+
*
|
|
853
|
+
* @param distancePx расстояние от камеры до тайла в мировых пикселях (`distanceToTile`)
|
|
854
|
+
*/
|
|
855
|
+
detailZoom(distancePx: number): number;
|
|
856
|
+
private _ensure;
|
|
857
|
+
private _calc;
|
|
858
|
+
private _calcCameraPosition;
|
|
859
|
+
/**
|
|
860
|
+
* Плоскости пирамиды видимости из обратной view-projection: берём 8 углов клипа,
|
|
861
|
+
* переводим в мир и строим 6 плоскостей с нормалями внутрь.
|
|
862
|
+
*/
|
|
863
|
+
private _calcFrustum;
|
|
864
|
+
/** Размер тайла зума z в пикселях экрана на расстоянии dist — критерий дробления. */
|
|
865
|
+
tileScreenSize(z: number, dist: number): number;
|
|
866
|
+
/** Сколько копий мира по X видно (панорама через антимеридиан). */
|
|
867
|
+
visibleWrapRange(): {
|
|
868
|
+
min: number;
|
|
869
|
+
max: number;
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
|
|
18
873
|
interface GestureOptions {
|
|
19
874
|
dragPan: boolean;
|
|
20
875
|
scrollZoom: boolean;
|
|
@@ -278,194 +1133,1970 @@ interface Capabilities {
|
|
|
278
1133
|
timerQuery: boolean;
|
|
279
1134
|
rendererName: string;
|
|
280
1135
|
/**
|
|
281
|
-
* Есть `KHR_parallel_shader_compile`: о готовности программы можно спросить, не дожидаясь её
|
|
282
|
-
* (см. `Shader.ready`). Без расширения такой вопрос сам ждёт конца компиляции.
|
|
1136
|
+
* Есть `KHR_parallel_shader_compile`: о готовности программы можно спросить, не дожидаясь её
|
|
1137
|
+
* (см. `Shader.ready`). Без расширения такой вопрос сам ждёт конца компиляции.
|
|
1138
|
+
*/
|
|
1139
|
+
parallelCompile: boolean;
|
|
1140
|
+
}
|
|
1141
|
+
type DepthFunc = 'less' | 'lequal' | 'always' | 'greater';
|
|
1142
|
+
type BlendMode = 'none' | 'alpha' | 'premultiplied' | 'add' | 'multiply';
|
|
1143
|
+
type CullMode = 'none' | 'back' | 'front';
|
|
1144
|
+
declare class Context {
|
|
1145
|
+
readonly gl: WebGL2RenderingContext;
|
|
1146
|
+
readonly caps: Capabilities;
|
|
1147
|
+
private _program;
|
|
1148
|
+
private _vao;
|
|
1149
|
+
private _framebuffer;
|
|
1150
|
+
private _depthTest;
|
|
1151
|
+
private _depthMask;
|
|
1152
|
+
private _colorMask;
|
|
1153
|
+
private _depthFunc;
|
|
1154
|
+
private _blend;
|
|
1155
|
+
private _cull;
|
|
1156
|
+
private _viewport;
|
|
1157
|
+
private _activeTexture;
|
|
1158
|
+
private _boundTextures;
|
|
1159
|
+
private _stencilTest;
|
|
1160
|
+
constructor(gl: WebGL2RenderingContext);
|
|
1161
|
+
/**
|
|
1162
|
+
* ЗАБЫТЬ ВСЁ, ЧТО МЫ ЗНАЛИ О СОСТОЯНИИ GL.
|
|
1163
|
+
*
|
|
1164
|
+
* Нужно после чужого кода — своего слоя приложения (`CustomLayerInterface`). Он вправе поменять
|
|
1165
|
+
* программу, буферы, смешивание и глубину; наш кеш после этого врёт, и следующий проход
|
|
1166
|
+
* «пропускает» установку, которой на самом деле нет. Дешевле объявить кеш недействительным, чем
|
|
1167
|
+
* потом искать, почему исчезли подписи.
|
|
1168
|
+
*/
|
|
1169
|
+
resetState(): void;
|
|
1170
|
+
useProgram(program: WebGLProgram | null): boolean;
|
|
1171
|
+
bindVAO(vao: WebGLVertexArrayObject | null): void;
|
|
1172
|
+
/**
|
|
1173
|
+
* Куда уходит «экранный» кадр. По умолчанию `null` — канва. Диагностика
|
|
1174
|
+
* подменяет его на свой буфер: проходы внутри рендера (тени, пикинг)
|
|
1175
|
+
* возвращаются с bindFramebuffer(null), и без этой подмены весь кадр после
|
|
1176
|
+
* первого же такого прохода уходил бы мимо буфера.
|
|
1177
|
+
*/
|
|
1178
|
+
screen: WebGLFramebuffer | null;
|
|
1179
|
+
/**
|
|
1180
|
+
* Привязанный сейчас кадровый буфер (этап e: проход в свою текстуру посреди кадра — плотность
|
|
1181
|
+
* тепловой карты, уклон отмывки — обязан вернуть ровно тот буфер, куда шёл кадр, в том числе
|
|
1182
|
+
* текстуру драпировки рельефа). `null` — канва (или `screen`).
|
|
1183
|
+
*/
|
|
1184
|
+
get currentFramebuffer(): WebGLFramebuffer | null;
|
|
1185
|
+
/** Текущий режим смешивания — чтобы проход, сменивший его на время, вернул прежний. */
|
|
1186
|
+
get blendMode(): BlendMode;
|
|
1187
|
+
bindFramebuffer(fb: WebGLFramebuffer | null): void;
|
|
1188
|
+
bindTexture(unit: number, texture: WebGLTexture | null, target?: number): void;
|
|
1189
|
+
/** Ширина и высота текущего вьюпорта (ещё не заданного — кадрового буфера), пиксели. */
|
|
1190
|
+
get viewportWidth(): number;
|
|
1191
|
+
get viewportHeight(): number;
|
|
1192
|
+
viewport(x: number, y: number, w: number, h: number): void;
|
|
1193
|
+
setDepthTest(on: boolean): void;
|
|
1194
|
+
setDepthMask(on: boolean): void;
|
|
1195
|
+
/**
|
|
1196
|
+
* Запись цвета. Выключенная маска — это рисование «только в глубину»:
|
|
1197
|
+
* геометрия перекрывает то, что нарисуют дальше, но сама не видна (так
|
|
1198
|
+
* закрываются дырки в утопленных поверхностях — острова).
|
|
1199
|
+
*/
|
|
1200
|
+
setColorMask(on: boolean): void;
|
|
1201
|
+
/** Текущая функция глубины — чтобы проход, сменивший её на время, вернул прежнюю. */
|
|
1202
|
+
get depthFunc(): DepthFunc;
|
|
1203
|
+
setDepthFunc(f: DepthFunc): void;
|
|
1204
|
+
setBlend(mode: BlendMode): void;
|
|
1205
|
+
setCull(mode: CullMode): void;
|
|
1206
|
+
setStencilTest(on: boolean): void;
|
|
1207
|
+
clear(color: [number, number, number, number] | null, depth?: boolean, stencil?: boolean): void;
|
|
1208
|
+
/** Сбрасывает кеш — вызывать после чужого кода, трогавшего контекст напрямую. */
|
|
1209
|
+
invalidateState(): void;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Скомпилированная программа с кешем локаций.
|
|
1214
|
+
*
|
|
1215
|
+
* `defines` подставляются в начало обоих шейдеров — так один исходник даёт варианты
|
|
1216
|
+
* (с тенями / без, с пикингом / без) без ветвления в горячем цикле фрагмента.
|
|
1217
|
+
*/
|
|
1218
|
+
declare class Shader {
|
|
1219
|
+
private ctx;
|
|
1220
|
+
readonly name: string;
|
|
1221
|
+
private readonly _program;
|
|
1222
|
+
private uniforms;
|
|
1223
|
+
private attribs;
|
|
1224
|
+
/**
|
|
1225
|
+
* ПОСЛЕДНЕЕ, ЧТО ПОЛОЖИЛИ В КАЖДЫЙ ЮНИФОРМ (перенос `Shader.kt` порта Android, 18.10.2026).
|
|
1226
|
+
*
|
|
1227
|
+
* Юниформ — состояние ПРОГРАММЫ: значение лежит там, пока его не сменят, а рендерер льёт их на каждую отрисовку:
|
|
1228
|
+
* цвет, ширина и пороги зума у слоя одни на все его тайлы, меняется только матрица. На Android кеш снял 1457 → 669
|
|
1229
|
+
* вызовов на кадр из 101 отрисовки; в WebGL каждый `uniform*` — проверка и запись в буфер команд браузера. Натив
|
|
1230
|
+
* решает то же блоками по частоте (`OsmglFrame`/`OsmglMaterial`), у GL — вот этот кеш.
|
|
1231
|
+
*
|
|
1232
|
+
* Безопасно потому, что значения принадлежат объекту программы, а менять их может только `uniform*` по ней — то
|
|
1233
|
+
* есть только сеттеры ниже; перелинковки нет, потеря контекста заводит `Shader` заново. Ключ — само место
|
|
1234
|
+
* юниформа (`WebGLUniformLocation`), значения — копией (рендерер правит матрицы на месте). Сравнение — по
|
|
1235
|
+
* числам JS, без `fround`: два разных числа с одним `float32` уйдут дважды, но лишнего не сэкономим никогда.
|
|
1236
|
+
* Целые — отдельно: `Float64Array` с ними не путается, но `uniform1i` и `uniform1f` — разные вызовы.
|
|
1237
|
+
*/
|
|
1238
|
+
private values;
|
|
1239
|
+
private ints;
|
|
1240
|
+
/** Сколько вызовов `uniform*` не ушло в GL: значение уже лежало в программе. */
|
|
1241
|
+
savedUniforms: number;
|
|
1242
|
+
/**
|
|
1243
|
+
* Сборка ещё не проверена: шейдеры лежат здесь до первого обращения к программе.
|
|
1244
|
+
*
|
|
1245
|
+
* ★ ПРОВЕРКА ОТЛОЖЕНА НАМЕРЕННО (03.10.2026). Конструктор раньше сразу спрашивал
|
|
1246
|
+
* `COMPILE_STATUS`/`LINK_STATUS`, а этот вопрос ЖДЁТ конца компиляции в главном потоке. Программ
|
|
1247
|
+
* при создании карты два десятка, и они собирались строго по очереди: 24 ожидания на 0.8–0.9 с
|
|
1248
|
+
* одной задачей (замер: холодный профиль Chromium, D3D11). Теперь все программы сначала
|
|
1249
|
+
* отправляются компилятору, и он собирает их в своих потоках одновременно, а ждём мы только ту, что
|
|
1250
|
+
* понадобилась первой (`finish`), — к тому моменту остальные уже в работе или готовы.
|
|
1251
|
+
*/
|
|
1252
|
+
private pending;
|
|
1253
|
+
constructor(ctx: Context, name: string, vertexSource: string, fragmentSource: string, defines?: Record<string, string | number | boolean>,
|
|
1254
|
+
/**
|
|
1255
|
+
* Места атрибутов, которые надо повторить, — у ВАРИАНТА программы (см. surfaceShader): VAO
|
|
1256
|
+
* собран по местам базовой программы и обязан подойти каждому варианту. Общий список мест
|
|
1257
|
+
* (ATTRIB_SLOTS) тут не годится: атрибутов больше, чем гарантированных шестнадцати мест.
|
|
1258
|
+
*/
|
|
1259
|
+
bind?: ReadonlyMap<string, number>);
|
|
1260
|
+
/** Программа GL. Первое обращение дожидается сборки (см. `pending`). */
|
|
1261
|
+
get program(): WebGLProgram;
|
|
1262
|
+
/** Сборка не удалась: каждое следующее обращение бросает ту же ошибку, а не рисует удалённой программой. */
|
|
1263
|
+
private failure;
|
|
1264
|
+
/**
|
|
1265
|
+
* Собрана ли программа — НЕ дожидаясь её, если драйвер это умеет (`KHR_parallel_shader_compile`).
|
|
1266
|
+
* Без расширения честного неблокирующего ответа нет, и программа считается готовой: тогда первое
|
|
1267
|
+
* обращение просто подождёт, как и раньше.
|
|
1268
|
+
*/
|
|
1269
|
+
get ready(): boolean;
|
|
1270
|
+
/** Дождаться сборки, проверить её и разобрать места юниформов и атрибутов. */
|
|
1271
|
+
private finish;
|
|
1272
|
+
private cacheLocations;
|
|
1273
|
+
use(): void;
|
|
1274
|
+
attribLocation(name: string): number;
|
|
1275
|
+
private loc;
|
|
1276
|
+
/** Надо ли слать значение в GL: `false` — там уже лежит такое же. */
|
|
1277
|
+
private changed;
|
|
1278
|
+
private readonly scratch;
|
|
1279
|
+
private changed4;
|
|
1280
|
+
/** Юниформ, вырезанный оптимизатором, молча игнорируется — это нормально. */
|
|
1281
|
+
setMat4(name: string, v: Float32Array): void;
|
|
1282
|
+
/** mat3 по КОЛОНКАМ — как того ждёт GLSL. */
|
|
1283
|
+
setMat3(name: string, v: ArrayLike<number>): void;
|
|
1284
|
+
setFloat(name: string, v: number): void;
|
|
1285
|
+
setInt(name: string, v: number): void;
|
|
1286
|
+
setVec2(name: string, x: number, y: number): void;
|
|
1287
|
+
setVec3(name: string, x: number, y: number, z: number): void;
|
|
1288
|
+
setVec4(name: string, x: number, y: number, z: number, w: number): void;
|
|
1289
|
+
setVec4v(name: string, v: ArrayLike<number>): void;
|
|
1290
|
+
/**
|
|
1291
|
+
* МАССИВ vec4 одним вызовом. Имя — без индекса: драйвер отдаёт локацию массива по `u_name[0]`,
|
|
1292
|
+
* но ищем мы и по голому имени, потому что часть драйверов регистрирует его именно так.
|
|
1293
|
+
*
|
|
1294
|
+
* Нужен для источников света модели: их до восьми, и восемь отдельных `uniform4f` на каждый
|
|
1295
|
+
* примитив — это восемь вызовов GL там, где хватает одного.
|
|
1296
|
+
*/
|
|
1297
|
+
setVec4Array(name: string, v: Float32Array): void;
|
|
1298
|
+
/** Массив float одним вызовом (этап c: длины пунктира) — как `setVec4Array`. */
|
|
1299
|
+
setFloatArray(name: string, v: Float32Array): void;
|
|
1300
|
+
destroy(): void;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
/**
|
|
1304
|
+
* СВОИ ПРОТОКОЛЫ ЗАГРУЗКИ И ПРАВКА ЗАПРОСОВ.
|
|
1305
|
+
*
|
|
1306
|
+
* Два разных вопроса, но оба про «откуда берутся байты тайла»:
|
|
1307
|
+
*
|
|
1308
|
+
* `addProtocol('pmtiles', …)` — адрес вида `pmtiles://…` обслуживает приложение само: читает из
|
|
1309
|
+
* одного файла, из IndexedDB, из WebAssembly-читалки;
|
|
1310
|
+
*
|
|
1311
|
+
* `setTransformRequest(fn)` — обычный адрес, но перед отправкой его правят: подписывают, меняют
|
|
1312
|
+
* домен, добавляют ключ.
|
|
1313
|
+
*
|
|
1314
|
+
* ★ И ТО И ДРУГОЕ ЖИВЁТ НА ГЛАВНОМ ПОТОКЕ.
|
|
1315
|
+
*
|
|
1316
|
+
* Так же у MapLibre, и по той же причине: обработчик приложенческий — ему нужны ключи, кеш и
|
|
1317
|
+
* хранилища страницы. Требовать, чтобы он работал внутри воркера, значит требовать от приложения
|
|
1318
|
+
* писать под воркер. Поэтому байты добываются здесь, а воркеру достаётся только разбор.
|
|
1319
|
+
*/
|
|
1320
|
+
/** Что обработчик протокола отдаёт: содержимое тайла или `null`, если тайла нет. */
|
|
1321
|
+
type ProtocolHandler = (url: string, signal: AbortSignal) => Promise<ArrayBuffer | null>;
|
|
1322
|
+
/** Правка адреса перед загрузкой. Возврат `null` означает «оставить как есть». */
|
|
1323
|
+
type TransformRequest = (url: string, kind: 'tile' | 'raster' | 'glyph' | 'sprite') => string | null | undefined;
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* Формат стиля движка.
|
|
1327
|
+
*
|
|
1328
|
+
* Сознательно НЕ повторяет style spec MapLibre: там половина возможностей
|
|
1329
|
+
* (символы, sprite, expressions полного вида) нам сейчас не нужна, а тащить их
|
|
1330
|
+
* означало бы тащить и интерпретатор выражений. Здесь — минимум, который
|
|
1331
|
+
* покрывает схему OpenMapTiles v3: фильтр по свойствам, значение по зуму,
|
|
1332
|
+
* три типа слоёв.
|
|
1333
|
+
*
|
|
1334
|
+
* Стиль хранится в `styles/*.json` и целиком вшивается в бандл — карта должна
|
|
1335
|
+
* рисоваться без единого сетевого запроса за конфигом.
|
|
1336
|
+
*/
|
|
1337
|
+
/**
|
|
1338
|
+
* Цвет, ВЫВЕДЕННЫЙ ИЗ ЦВЕТА ДРУГОГО СЛОЯ: «как у него, только темнее».
|
|
1339
|
+
*
|
|
1340
|
+
* Нужен обводке моста. Собственный цвет ей задать нельзя: тем два десятка, каждая красит дороги
|
|
1341
|
+
* по-своему, и любой фиксированный хекс на половине из них смотрелся бы чужим. Полупрозрачная
|
|
1342
|
+
* затемняющая краска эту задачу решала, но полупрозрачной линии нельзя: капсулы соседних отрезков
|
|
1343
|
+
* перекрываются на изломах, и краска ложится дважды — по вершинам идёт цепочка тёмных бусин.
|
|
1344
|
+
* (Трафарет «красить пиксель один раз» бусины убирает, но взамен оставляет светлый шов по
|
|
1345
|
+
* сглаженному краю первой капсулы — проверено.)
|
|
1346
|
+
*
|
|
1347
|
+
* Ссылка снимает вопрос: тема красит обводку дороги, а обводка моста едет следом сама.
|
|
1348
|
+
*/
|
|
1349
|
+
interface ColorFrom {
|
|
1350
|
+
/** Идентификатор слоя, у которого берём цвет. */
|
|
1351
|
+
from: string;
|
|
1352
|
+
/** Насколько затемнить, 0..1 (0.25 — четверть). */
|
|
1353
|
+
darken?: number;
|
|
1354
|
+
/**
|
|
1355
|
+
* Какое свойство покраски слоя-источника брать; по умолчанию `color`. Плоские здания мелкого зума
|
|
1356
|
+
* берут `roofColor` объёмного слоя: сверху у дома видна крыша, и темы красят её отдельно.
|
|
1357
|
+
*/
|
|
1358
|
+
property?: string;
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Значение, зависящее от зума.
|
|
1362
|
+
*
|
|
1363
|
+
* Три формы, и все три равноправны:
|
|
1364
|
+
* само значение — `14`, `'#fff'`;
|
|
1365
|
+
* наши остановки — `{ stops: [[10, 2], [16, 8]] }`, короткая запись линейной шкалы;
|
|
1366
|
+
* выражение MapLibre — `['interpolate', ['linear'], ['zoom'], 10, 2, 16, 8]`.
|
|
1367
|
+
*
|
|
1368
|
+
* Выражения добавлены не вместо остановок, а рядом: на остановках написаны все наши стили, а на
|
|
1369
|
+
* выражениях — всё, что приходит снаружи. Выбирать между ними не должно приходиться ни приложению,
|
|
1370
|
+
* ни теме (см. `style/expression.ts`).
|
|
1371
|
+
*/
|
|
1372
|
+
type Interpolated<T> = T | {
|
|
1373
|
+
stops: [number, T][];
|
|
1374
|
+
} | unknown[];
|
|
1375
|
+
/**
|
|
1376
|
+
* Фильтр по свойствам фичи. Подмножество синтаксиса MapLibre — ровно то,
|
|
1377
|
+
* что встречается в схеме OMT.
|
|
1378
|
+
*
|
|
1379
|
+
* ['==', 'class', 'motorway']
|
|
1380
|
+
* ['in', 'class', 'primary', 'secondary']
|
|
1381
|
+
* ['has', 'name']
|
|
1382
|
+
* ['all', [...], [...]]
|
|
1383
|
+
*/
|
|
1384
|
+
type Filter = ['==' | '!=' | '>' | '>=' | '<' | '<=', string, string | number | boolean] | ['in' | '!in', string, ...(string | number | boolean)[]] | ['has' | '!has', string] | ['all' | 'any', ...Filter[]] | ['!', Filter]
|
|
1385
|
+
/**
|
|
1386
|
+
* Выражение MapLibre: `['==', ['get', 'class'], 'primary']` и любое другое.
|
|
1387
|
+
*
|
|
1388
|
+
* Отличается от старой формы тем, что на месте имени свойства стоит вложенное выражение — по
|
|
1389
|
+
* этому признаку они и различаются при разборе (см. `matchesFilter`).
|
|
1390
|
+
*/
|
|
1391
|
+
| unknown[]
|
|
1392
|
+
/** То же, записанное `as const` (02.11.2026): массив только для чтения тоже фильтр. */
|
|
1393
|
+
| readonly unknown[];
|
|
1394
|
+
interface LayerBase {
|
|
1395
|
+
id: string;
|
|
1396
|
+
/**
|
|
1397
|
+
* Источник тайлов. По умолчанию `base` — основная карта. Планы этажей лежат
|
|
1398
|
+
* в отдельном наборе (`indoor.mbtiles`, зумы 15–18), и смешивать их с основным
|
|
1399
|
+
* нельзя: у наборов разные потолки зума и разная частота пересборки.
|
|
1400
|
+
*/
|
|
1401
|
+
source?: string;
|
|
1402
|
+
/** Слой MVT, откуда брать фичи. */
|
|
1403
|
+
'source-layer': string;
|
|
1404
|
+
filter?: Filter;
|
|
1405
|
+
minzoom?: number;
|
|
1406
|
+
maxzoom?: number;
|
|
1407
|
+
/**
|
|
1408
|
+
* Разбить слой на отдельные меши по значению этого свойства фичи.
|
|
1409
|
+
*
|
|
1410
|
+
* Нужно этажам. Фильтры у нас применяются в ВОРКЕРЕ, на этапе тесселяции,
|
|
1411
|
+
* поэтому «просто дописать `level == 3` в фильтр» означало бы пересобирать
|
|
1412
|
+
* геометрию всех тайлов на каждое переключение этажа. Разбив слой заранее,
|
|
1413
|
+
* переключение сводится к выбору другого готового буфера — как с темами,
|
|
1414
|
+
* которые тоже ничего не пересобирают.
|
|
1415
|
+
*/
|
|
1416
|
+
splitBy?: string;
|
|
1417
|
+
/**
|
|
1418
|
+
* Накладка: слой рисуется вне общей очереди, без теста глубины. Значение говорит, ГДЕ.
|
|
1419
|
+
*
|
|
1420
|
+
* `'volume'` (и `true` — прежнее написание) — поверх объёма. Нужно планам этажей: они лежат
|
|
1421
|
+
* внутри здания, и в обычном порядке их закрыла бы его крыша. План этажа и есть накладка —
|
|
1422
|
+
* «мы внутри», — а покрывает он ровно контур своего здания, поэтому соседние дома остаются
|
|
1423
|
+
* видимыми.
|
|
1424
|
+
*
|
|
1425
|
+
* `'roads'` — сразу после дорог и ДО объёма. Это место разметки: зебры, перекрытия, всё, что
|
|
1426
|
+
* лежит на асфальте. Дороги рисуются позже поверхностей, поэтому в общую очередь такая
|
|
1427
|
+
* разметка не встаёт, но и поверх объёма ей делать нечего — зебра, висящая на стене дома,
|
|
1428
|
+
* первой бросается в глаза.
|
|
1429
|
+
*
|
|
1430
|
+
* `'route'` — ВМЕСТЕ С ЛИНИЕЙ МАРШРУТА, в проходе рантайм-объектов (после объёма), и в отличие от
|
|
1431
|
+
* остальных накладок — С ТЕСТОМ ГЛУБИНЫ, сдвинутой к камере на долю расстояния (`DEPTH_NUDGE`, как
|
|
1432
|
+
* у `LineLayerSpec.depthTest`): асфальт, разметка и плиты полотна в сантиметрах ниже слой не
|
|
1433
|
+
* закрывают (раньше лента по полосам рябила и пропадала кусками на настиле и детальных дорогах),
|
|
1434
|
+
* а дом впереди и настил эстакады в метрах над ним — закрывают. Глубину не пишет. Между объектами:
|
|
1435
|
+
* объекты с `zIndex` ниже `ROUTE_OVERLAY_Z` (невыбранные варианты) — под слоем, остальные (линия,
|
|
1436
|
+
* пройденная часть, стрелки поворотов) — над ним. Так рисуется лента по полосам — продолжение линии.
|
|
1437
|
+
*/
|
|
1438
|
+
overlay?: boolean | 'roads' | 'volume' | 'route';
|
|
1439
|
+
/** Выключить слой, не удаляя из стиля. */
|
|
1440
|
+
visible?: boolean;
|
|
1441
|
+
/** Свободные данные приложения у слоя (`metadata` слоя MapLibre). Движок их не читает. */
|
|
1442
|
+
metadata?: Record<string, unknown>;
|
|
1443
|
+
/** Плавная смена свойств покраски по полю (`*-transition` MapLibre, этап d) — главнее `transition` корня. */
|
|
1444
|
+
paintTransition?: Record<string, TransitionSpec>;
|
|
1445
|
+
/**
|
|
1446
|
+
* Радиус скругления углов в МЕТРАХ (заливки и объём).
|
|
1447
|
+
*
|
|
1448
|
+
* Это ГЕОМЕТРИЯ, а не покраска: правка радиуса пересобирает тайлы, как и
|
|
1449
|
+
* правка фильтра. Поэтому свойство лежит рядом с фильтром, а не в `paint` —
|
|
1450
|
+
* там всё меняется одними юниформами, без пересборки.
|
|
1451
|
+
*
|
|
1452
|
+
* У здания скругляется контур, а значит и стены, и КРЫША: она строится по
|
|
1453
|
+
* тому же кольцу. На границе тайла срез не делается — иначе половинки дома
|
|
1454
|
+
* из соседних тайлов сошлись бы со ступенькой.
|
|
1455
|
+
*/
|
|
1456
|
+
cornerRadius?: number;
|
|
1457
|
+
/**
|
|
1458
|
+
* Крыши только плоские — как у `fill-extrusion` MapLibre. По умолчанию невысокий дом простой
|
|
1459
|
+
* формы получает скатную крышу (по тегу `roof_shape` или по размеру); стилю, пришедшему из
|
|
1460
|
+
* MapLibre, это чужой облик. Геометрия — поэтому поле рядом с фильтром, а не в `paint`.
|
|
1461
|
+
*/
|
|
1462
|
+
flatRoofs?: boolean;
|
|
1463
|
+
/**
|
|
1464
|
+
* СВЕТ ОБЪЁМА ПО МОДЕЛИ MapLibre (`'maplibre'`) — у `fill-extrusion`, пришедшего из стиля MapLibre.
|
|
1465
|
+
*
|
|
1466
|
+
* Цвет вершины считается ровно формулой `fill_extrusion.vertex.glsl`: яркость цвета, подсветка
|
|
1467
|
+
* 0.03, один направленный источник из `StyleSpec.mapLibreLight`, градиент стены по высоте. Наш
|
|
1468
|
+
* свет, затенение у основания, тени, дымка, стекло и разброс тона такой слой не получает вовсе —
|
|
1469
|
+
* у MapLibre их нет, и «похожий» облик был бы другим цветом каждой грани.
|
|
1470
|
+
*
|
|
1471
|
+
* Поле не только покраска, но и ГЕОМЕТРИЯ: нормали стен у такого слоя плоские на каждое ребро, как
|
|
1472
|
+
* у MapLibre (`fill_extrusion_bucket`), без нашего сглаживания на пологих изломах. Поэтому оно
|
|
1473
|
+
* лежит рядом с фильтром и едет в план воркера.
|
|
1474
|
+
*/
|
|
1475
|
+
lighting?: 'maplibre';
|
|
1476
|
+
/**
|
|
1477
|
+
* Обрезать заливку по квадрату тайла.
|
|
1478
|
+
*
|
|
1479
|
+
* Нужно ПОЛУПРОЗРАЧНЫМ слоям: тайл приходит с буфером, полигон у границы
|
|
1480
|
+
* приезжает и сюда, и к соседу, и в полосе перекрытия прозрачная заливка
|
|
1481
|
+
* ложится дважды — по стыку идёт полоса иной плотности. Непрозрачной заливке
|
|
1482
|
+
* буфер, наоборот, полезен: он закрывает волосяные щели на стыке.
|
|
1483
|
+
*/
|
|
1484
|
+
clipToTile?: boolean;
|
|
1485
|
+
/**
|
|
1486
|
+
* Класс поверхности → её уровень в метрах: по нему РАЗМЕТКА поднимается вместе с дорогой.
|
|
1487
|
+
*
|
|
1488
|
+
* Зебра перехода живёт в своём наборе тайлов, где никаких газонов и парковок нет, и высоту под
|
|
1489
|
+
* собой посчитать не может (в отличие от дороги, см. `generators/ground`). Зато база знает, в
|
|
1490
|
+
* каком полигоне лежит переход, и кладёт его класс в свойство `on` — `слой:класс`, теми же
|
|
1491
|
+
* словами, что и тайлы. Таблица переводит класс в высоту, а собирают её скрипты стилей из
|
|
1492
|
+
* уровней тех же самых поверхностей, чтобы числа не разъезжались.
|
|
1493
|
+
*/
|
|
1494
|
+
groundBy?: Record<string, number>;
|
|
1495
|
+
/** Максимум отрезков на одну дугу (по умолчанию 4). */
|
|
1496
|
+
cornerSegments?: number;
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Материал плоского слоя — «из чего он сделан».
|
|
1500
|
+
*
|
|
1501
|
+
* По умолчанию материала нет: слой рисуется сплошной заливкой, ровно как
|
|
1502
|
+
* раньше, и не стоит ни одной лишней инструкции в шейдере. Остальные варианты
|
|
1503
|
+
* дают поверхности микрорельеф, а значит светотень: у сплошной заливки нормали
|
|
1504
|
+
* нет вовсе, поэтому свет на неё не ложится и карта читается бумажной.
|
|
1505
|
+
*
|
|
1506
|
+
* Настраивается ИЗ СТИЛЯ (и переопределяется темой — это те же paint-поля):
|
|
1507
|
+
* "paint": { "color": "#a5cbe3", "material": "water", "materialScale": 9 }
|
|
1508
|
+
*/
|
|
1509
|
+
type MaterialName = 'flat' | 'water' | 'foliage' | 'sand' | 'asphalt';
|
|
1510
|
+
/** Общие настройки материала. Ими правят вид, не трогая сам движок. */
|
|
1511
|
+
interface MaterialPaint {
|
|
1512
|
+
material?: MaterialName;
|
|
1513
|
+
/** Выраженность рисунка, 0..1. Ноль — тот же сплошной цвет. */
|
|
1514
|
+
materialStrength?: Interpolated<number>;
|
|
1515
|
+
/** Размер рисунка в метрах: у воды это длина волны, у зелени — размер крон. */
|
|
1516
|
+
materialScale?: Interpolated<number>;
|
|
1517
|
+
/** Скорость анимации (вода). Ноль — статичная поверхность без перерисовок. */
|
|
1518
|
+
materialSpeed?: Interpolated<number>;
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Растровая подложка.
|
|
1522
|
+
*
|
|
1523
|
+
* Слой особый: у него нет ни фильтра, ни слоя MVT — рисуется весь тайл целиком.
|
|
1524
|
+
* Поэтому он и не наследует `LayerBase`, где `source-layer` обязателен.
|
|
1525
|
+
*/
|
|
1526
|
+
interface RasterLayerSpec {
|
|
1527
|
+
id: string;
|
|
1528
|
+
type: 'raster';
|
|
1529
|
+
/** Имя растрового источника. Обязательно: подложка не бывает «из основного». */
|
|
1530
|
+
source: string;
|
|
1531
|
+
minzoom?: number;
|
|
1532
|
+
maxzoom?: number;
|
|
1533
|
+
visible?: boolean;
|
|
1534
|
+
/** Свободные данные приложения у слоя (`metadata` слоя MapLibre). Движок их не читает. */
|
|
1535
|
+
metadata?: Record<string, unknown>;
|
|
1536
|
+
/** Плавная смена свойств покраски по полю (этап d) — как у `LayerBase`. */
|
|
1537
|
+
paintTransition?: Record<string, TransitionSpec>;
|
|
1538
|
+
/**
|
|
1539
|
+
* Рисовать ПОВЕРХ векторной карты, а не под ней.
|
|
1540
|
+
*
|
|
1541
|
+
* Подложка по смыслу лежит внизу, но растровым бывает и слой ПОВЕРХ: пробки,
|
|
1542
|
+
* снимки событий, любая картинка, которую рисует сервер. Разделяет их только
|
|
1543
|
+
* этот признак — конвейер у них общий.
|
|
1544
|
+
*/
|
|
1545
|
+
overlay?: boolean;
|
|
1546
|
+
paint?: {
|
|
1547
|
+
opacity?: Interpolated<number>;
|
|
1548
|
+
/** Поворот тона, градусы (`raster-hue-rotate`). */
|
|
1549
|
+
hueRotate?: Interpolated<number>;
|
|
1550
|
+
/** Яркость: чёрное → `brightnessMin`, белое → `brightnessMax` (0..1). */
|
|
1551
|
+
brightnessMin?: Interpolated<number>;
|
|
1552
|
+
brightnessMax?: Interpolated<number>;
|
|
1553
|
+
/** Насыщенность, −1..1 (`raster-saturation`). */
|
|
1554
|
+
saturation?: Interpolated<number>;
|
|
1555
|
+
/** Контраст, −1..1 (`raster-contrast`). */
|
|
1556
|
+
contrast?: Interpolated<number>;
|
|
1557
|
+
/** Выборка текстуры при увеличении: `linear` или `nearest` (`raster-resampling`). */
|
|
1558
|
+
resampling?: 'linear' | 'nearest';
|
|
1559
|
+
/** Проявление нового тайла, мс (`raster-fade-duration`); 0 — сразу. */
|
|
1560
|
+
fadeDuration?: Interpolated<number>;
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Круги в точках (и в вершинах линий и полигонов) — слой `circle` MapLibre: заливка, обводка
|
|
1565
|
+
* СНАРУЖИ радиуса, размытие всего круга. Значения — по зуму и по фиче.
|
|
1566
|
+
*/
|
|
1567
|
+
interface CircleLayerSpec extends LayerBase {
|
|
1568
|
+
type: 'circle';
|
|
1569
|
+
paint: {
|
|
1570
|
+
radius?: Interpolated<number>;
|
|
1571
|
+
color?: Interpolated<string>;
|
|
1572
|
+
blur?: Interpolated<number>;
|
|
1573
|
+
opacity?: Interpolated<number>;
|
|
1574
|
+
strokeWidth?: Interpolated<number>;
|
|
1575
|
+
strokeColor?: Interpolated<string>;
|
|
1576
|
+
strokeOpacity?: Interpolated<number>;
|
|
1577
|
+
translate?: Interpolated<[number, number]>;
|
|
1578
|
+
translateAnchor?: 'map' | 'viewport';
|
|
1579
|
+
/** `map` — круг сокращается с перспективой, `viewport` — одного размера на экране. */
|
|
1580
|
+
pitchScale?: 'map' | 'viewport';
|
|
1581
|
+
/** `map` — круг лежит на земле, `viewport` — смотрит в экран. */
|
|
1582
|
+
pitchAlignment?: 'map' | 'viewport';
|
|
1583
|
+
};
|
|
1584
|
+
/** Порядок кругов внутри слоя (`circle-sort-key`). */
|
|
1585
|
+
sortKey?: unknown;
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* Фон слоем — `background` MapLibre: заливка всего кадра на своём месте в списке слоёв, цвет и
|
|
1589
|
+
* прозрачность по зуму, узор из спрайта. Фон корня (`StyleSpec.background`) остаётся: в него
|
|
1590
|
+
* загрузчик кладёт ПЕРВЫЙ постоянный фон стиля, как и прежде.
|
|
1591
|
+
*/
|
|
1592
|
+
interface BackgroundLayerSpec {
|
|
1593
|
+
id: string;
|
|
1594
|
+
type: 'background';
|
|
1595
|
+
/** Источника у фона нет — поле только чтобы общий код читал `layer.source` без разбора типа. */
|
|
1596
|
+
source?: never;
|
|
1597
|
+
overlay?: never;
|
|
1598
|
+
minzoom?: number;
|
|
1599
|
+
maxzoom?: number;
|
|
1600
|
+
visible?: boolean;
|
|
1601
|
+
metadata?: Record<string, unknown>;
|
|
1602
|
+
/** Плавная смена свойств покраски по полю (этап d) — как у `LayerBase`. */
|
|
1603
|
+
paintTransition?: Record<string, TransitionSpec>;
|
|
1604
|
+
paint: {
|
|
1605
|
+
color?: Interpolated<string>;
|
|
1606
|
+
opacity?: Interpolated<number>;
|
|
1607
|
+
pattern?: unknown;
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* ПЛАВНАЯ СМЕНА СВОЙСТВА (`transition` MapLibre, этап d): за `duration` мс после `delay` мс.
|
|
1612
|
+
* Без поля у стиля MapLibre — 300/0, у своего стиля osmgl — сразу (`style/transition.ts`).
|
|
1613
|
+
*/
|
|
1614
|
+
interface TransitionSpec {
|
|
1615
|
+
duration?: number;
|
|
1616
|
+
delay?: number;
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* Тепловая карта — слой `heatmap` MapLibre: ядро Гаусса на каждую точку складывается в плотность
|
|
1620
|
+
* (своя текстура в четверть экрана), плотность красится шкалой `heatmap-color`. Радиус и вес — по
|
|
1621
|
+
* зуму и по фиче; сила, шкала и прозрачность — по зуму.
|
|
1622
|
+
*/
|
|
1623
|
+
interface HeatmapLayerSpec extends LayerBase {
|
|
1624
|
+
type: 'heatmap';
|
|
1625
|
+
paint: {
|
|
1626
|
+
/** Радиус ядра, CSS-пиксели (`heatmap-radius`). */
|
|
1627
|
+
radius?: Interpolated<number>;
|
|
1628
|
+
/** Вес точки (`heatmap-weight`). */
|
|
1629
|
+
weight?: Interpolated<number>;
|
|
1630
|
+
/** Множитель плотности (`heatmap-intensity`), только по зуму. */
|
|
1631
|
+
intensity?: Interpolated<number>;
|
|
1632
|
+
/** Цвет по плотности: выражение от `["heatmap-density"]` (`heatmap-color`). */
|
|
1633
|
+
color?: unknown;
|
|
1634
|
+
opacity?: Interpolated<number>;
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
/** Общие поля слоёв по источнику высот (`raster-dem`): фичи и фильтра у них нет, как у растра. */
|
|
1638
|
+
interface DemLayerBase {
|
|
1639
|
+
id: string;
|
|
1640
|
+
/** Имя источника типа `raster-dem`. */
|
|
1641
|
+
source: string;
|
|
1642
|
+
minzoom?: number;
|
|
1643
|
+
maxzoom?: number;
|
|
1644
|
+
visible?: boolean;
|
|
1645
|
+
metadata?: Record<string, unknown>;
|
|
1646
|
+
overlay?: never;
|
|
1647
|
+
}
|
|
1648
|
+
/**
|
|
1649
|
+
* Отмывка рельефа плоским слоем — `hillshade` MapLibre по тайлам `raster-dem`: уклон считается из
|
|
1650
|
+
* высот (подготовка в текстуру тайла), свет — одним из пяти методов MapLibre 5.
|
|
1651
|
+
*/
|
|
1652
|
+
interface HillshadeLayerSpec extends DemLayerBase {
|
|
1653
|
+
type: 'hillshade';
|
|
1654
|
+
paint: {
|
|
1655
|
+
/** Азимут света, градусы; массив — несколько источников (метод `multidirectional`). */
|
|
1656
|
+
illuminationDirection?: Interpolated<number> | number[];
|
|
1657
|
+
/** Высота света над горизонтом, градусы (не у `standard`). */
|
|
1658
|
+
illuminationAltitude?: Interpolated<number> | number[];
|
|
1659
|
+
/** `viewport` — свет поворачивается с экраном, `map` — стоит на карте. */
|
|
1660
|
+
illuminationAnchor?: 'map' | 'viewport';
|
|
1661
|
+
exaggeration?: Interpolated<number>;
|
|
1662
|
+
shadowColor?: Interpolated<string> | string[];
|
|
1663
|
+
highlightColor?: Interpolated<string> | string[];
|
|
1664
|
+
accentColor?: Interpolated<string>;
|
|
1665
|
+
method?: 'standard' | 'basic' | 'combined' | 'igor' | 'multidirectional';
|
|
1666
|
+
/** Выборка подготовленной текстуры при увеличении. */
|
|
1667
|
+
resampling?: 'linear' | 'nearest';
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
/** Гипсометрия плоским слоем — `color-relief` MapLibre: цвет пикселя по высоте из `raster-dem`. */
|
|
1671
|
+
interface ColorReliefLayerSpec extends DemLayerBase {
|
|
1672
|
+
type: 'color-relief';
|
|
1673
|
+
paint: {
|
|
1674
|
+
/** Цвет по высоте: `interpolate` от `["elevation"]` (`color-relief-color`). */
|
|
1675
|
+
color?: unknown;
|
|
1676
|
+
opacity?: Interpolated<number>;
|
|
1677
|
+
resampling?: 'linear' | 'nearest';
|
|
1678
|
+
};
|
|
1679
|
+
}
|
|
1680
|
+
/** Слои по источнику высот (этап e): без фич и без плана воркера, как растр. */
|
|
1681
|
+
type DemLayerSpec = HillshadeLayerSpec | ColorReliefLayerSpec;
|
|
1682
|
+
/** Слой по источнику высот (`hillshade`, `color-relief`) — этап (e). */
|
|
1683
|
+
declare function isDemLayer(layer: {
|
|
1684
|
+
type: string;
|
|
1685
|
+
}): layer is DemLayerSpec;
|
|
1686
|
+
interface FillLayerSpec extends LayerBase {
|
|
1687
|
+
type: 'fill';
|
|
1688
|
+
paint: MaterialPaint & {
|
|
1689
|
+
/** Цвет заливки; `{ from, property }` — «как у такого-то слоя» (плоские здания берут `roofColor`). */
|
|
1690
|
+
color: Interpolated<string> | ColorFrom;
|
|
1691
|
+
opacity?: Interpolated<number>;
|
|
1692
|
+
/**
|
|
1693
|
+
* Сглаживающий контур в 1 пиксель по краю заливки — `fill-antialias` MapLibre. Без поля — нет
|
|
1694
|
+
* (облик osmgl); импортёр стиля MapLibre ставит `true`, как умолчание спецификации.
|
|
1695
|
+
*/
|
|
1696
|
+
antialias?: boolean;
|
|
1697
|
+
/** Цвет контура (`fill-outline-color`); без поля — цвет заливки. Бывает по фиче. */
|
|
1698
|
+
outlineColor?: Interpolated<string>;
|
|
1699
|
+
/** Этап (d): прозрачность слоя ЦЕЛИКОМ (`fill-layer-opacity`) — без накопления на перекрытиях. */
|
|
1700
|
+
layerOpacity?: Interpolated<number>;
|
|
1701
|
+
/** Сдвиг заливки на экране, пиксели (`fill-translate`). */
|
|
1702
|
+
translate?: Interpolated<[number, number]>;
|
|
1703
|
+
/** `map` — сдвиг поворачивается с картой, `viewport` — по экрану (`fill-translate-anchor`). */
|
|
1704
|
+
translateAnchor?: 'map' | 'viewport';
|
|
1705
|
+
/** Узор из спрайта (`fill-pattern`): имя картинки или выражение (по зуму и по фиче). */
|
|
1706
|
+
pattern?: unknown;
|
|
1707
|
+
};
|
|
1708
|
+
/** Порядок фич внутри слоя (`fill-sort-key`): меньший рисуется раньше. Бывает по фиче. */
|
|
1709
|
+
sortKey?: unknown;
|
|
1710
|
+
}
|
|
1711
|
+
interface LineLayerSpec extends LayerBase {
|
|
1712
|
+
type: 'line';
|
|
1713
|
+
/**
|
|
1714
|
+
* СЕТЬ, внутри которой порядок отрисовки решают не слои, а уровни пересечения.
|
|
1715
|
+
*
|
|
1716
|
+
* Все дорожные слои стиля — обводки, полотна, тень моста — помечаются одним именем (`roads`), и
|
|
1717
|
+
* рисуются они не подряд, а по уровням: сначала вся сеть уровня −1 (тоннели), потом вся сеть
|
|
1718
|
+
* земли, потом вся сеть эстакад. Поэтому мост со своей тенью и обводкой ложится ЦЕЛИКОМ поверх
|
|
1719
|
+
* улицы под ним, какого бы класса та ни была, — а не «полотно моста поверх, обводка под».
|
|
1720
|
+
*
|
|
1721
|
+
* Так же устроено у Яндекса: у каждого дорожного слоя `line-network: "roads"` и
|
|
1722
|
+
* `line-z-level: ["get","z_level"]`. Уровень фичи считается по `generators/level`.
|
|
1723
|
+
*
|
|
1724
|
+
* Сеть рисуется целиком НА МЕСТЕ ПЕРВОГО своего слоя в стиле; порядок внутри уровня — обычный,
|
|
1725
|
+
* по порядку слоёв.
|
|
1726
|
+
*/
|
|
1727
|
+
network?: string;
|
|
1728
|
+
/**
|
|
1729
|
+
* УСТУПИТЬ МЕСТО ПОДРОБНОМУ СЛОЮ: id слоя-ПОВЕРХНОСТИ (`surface`), который рисует то же самое
|
|
1730
|
+
* точнее.
|
|
1731
|
+
*
|
|
1732
|
+
* Так живёт пара «линия дороги — асфальт»: у асфальта свой набор тайлов (с z15), и пока его тайл
|
|
1733
|
+
* не приехал, на его месте не должно быть пусто. Линия поэтому не выключается по зуму, а рисуется
|
|
1734
|
+
* везде, КРОМЕ квадратов, в которых подробный слой уже нарисован: там её закрывает трафарет
|
|
1735
|
+
* (`PAINTED_BIT`, см. `layers/renderer.ts`). Так же ведёт себя Baidu: грубая карта видна сразу, и
|
|
1736
|
+
* подробная ложится на неё кусками, по мере прихода (`useThumbData`).
|
|
1737
|
+
*
|
|
1738
|
+
* Уступка идёт ПО КВАДРАТУ ТАЙЛА, а не по пикселю асфальта. Линия дороги шире асфальта (её
|
|
1739
|
+
* ширина — приём картографии в пикселях, а не размер сооружения), и маска по самому асфальту
|
|
1740
|
+
* оставила бы вдоль каждой кромки полоску старой линии.
|
|
1741
|
+
*
|
|
1742
|
+
* Заодно это чинит дальний план наклонённой карты: подробный слой там гаснет по зуму детализации
|
|
1743
|
+
* (`Transform.detailZoom`), квадратов не размечает — и линия остаётся. Раньше линию гасили
|
|
1744
|
+
* `maxzoom` по зуму КАМЕРЫ, и при сильном наклоне дорога вдали пропадала совсем: асфальта уже нет,
|
|
1745
|
+
* линии ещё нет.
|
|
1746
|
+
*/
|
|
1747
|
+
yieldTo?: string;
|
|
1748
|
+
/**
|
|
1749
|
+
* ЛИНИЮ ЗАКРЫВАЕТ ТО, ЧТО НАД НЕЙ: краска на асфальте прячется под эстакадой, как в жизни.
|
|
1750
|
+
*
|
|
1751
|
+
* Поднятые линии рисуются без теста глубины: краска лежит на своём асфальте в сантиметрах, и такой
|
|
1752
|
+
* зазор буфер глубины не различает — линия мерцала бы на собственном полотне (см. проход поднятых
|
|
1753
|
+
* линий в `layers/renderer.ts`). Поэтому краска улицы под эстакадой проступала сквозь настил.
|
|
1754
|
+
*
|
|
1755
|
+
* С этим флагом линия проходит тест глубины, а её глубина сдвинута к камере на долю расстояния
|
|
1756
|
+
* (`DEPTH_NUDGE`): своё полотно в сантиметрах ниже её не закрывает, а настил в метрах над ней —
|
|
1757
|
+
* закрывает. Записи глубины нет, как и у всех поднятых линий. На шаре и в текстуре рельефа флаг
|
|
1758
|
+
* не действует: там глубины для такого сравнения нет.
|
|
1759
|
+
*/
|
|
1760
|
+
depthTest?: boolean;
|
|
1761
|
+
/**
|
|
1762
|
+
* ЛИНИЯ В ОЧЕРЕДИ ПОВЕРХНОСТЕЙ: поднятая линия рисуется не после ВСЕХ поверхностей, а на СВОЁМ МЕСТЕ
|
|
1763
|
+
* среди них, по порядку слоёв стиля.
|
|
1764
|
+
*
|
|
1765
|
+
* Поднятые линии идут отдельным проходом после поверхностей и без теста глубины — дорога лежит на газоне,
|
|
1766
|
+
* а не спорит с ним за глубину. Но так же она ложится и на асфальт полотна, а тротуар поверх проезжей
|
|
1767
|
+
* части — это пунктир через зебру. С флагом линия рисуется в очереди поверхностей: поверхности ДО неё
|
|
1768
|
+
* (земля, газон, двор) — под ней, поверхности ПОСЛЕ (асфальт полотна, детальных дорог) закрывают её своей
|
|
1769
|
+
* глубиной. Ровно как у стиля MapLibre, где пешеходная линия лежит под линией дороги по порядку слоёв.
|
|
1770
|
+
*
|
|
1771
|
+
* Рисуется без теста и без записи глубины, как поднятая линия (`depthTest` здесь не действует: всё, что
|
|
1772
|
+
* может её закрыть, идёт в очереди позже). В сеть (`network`) такая
|
|
1773
|
+
* линия не входит: место ей задаёт порядок стиля, а не уровень пересечения. Действует только у поднятой
|
|
1774
|
+
* линии (`elevation > 0`); у плоской место и так в плоском проходе. На рельефе — как прочие поднятые
|
|
1775
|
+
* (уезжает в текстуры тайлов).
|
|
1776
|
+
*/
|
|
1777
|
+
surfaceOrder?: boolean;
|
|
1778
|
+
paint: MaterialPaint & {
|
|
1779
|
+
/** Цвет линии; `{ from, darken }` — «как у такого-то слоя, только темнее» (см. `ColorFrom`). */
|
|
1780
|
+
color: Interpolated<string> | ColorFrom;
|
|
1781
|
+
/** Ширина в ЭКРАННЫХ пикселях: линия не толстеет с приближением к камере. */
|
|
1782
|
+
width: Interpolated<number>;
|
|
1783
|
+
opacity?: Interpolated<number>;
|
|
1784
|
+
/** Сдвиг поперёк линии в пикселях — для обочин и параллельных путей. */
|
|
1785
|
+
offset?: Interpolated<number>;
|
|
1786
|
+
/**
|
|
1787
|
+
* РАЗМЫТИЕ КРАЯ в пикселях: край растягивается на столько вместо обычного полупикселя.
|
|
1788
|
+
*
|
|
1789
|
+
* Нужно тени моста. У Яндекса тени нет вовсе как отдельной сущности — там на каждый мост
|
|
1790
|
+
* рисуется ВОСЕМЬ вложенных контуров (`road-sd-shadow-1…8__bridge`), каждый с прозрачностью
|
|
1791
|
+
* 0.03–0.08, и их сумма изображает размытие. Это обход отсутствующего в их движке размытия:
|
|
1792
|
+
* восемь слоёв в стиле и восемь вызовов отрисовки на тайл ради градиента.
|
|
1793
|
+
*
|
|
1794
|
+
* У нас край линии и так вырезает фрагментный шейдер по расстоянию до оси — растянуть переход
|
|
1795
|
+
* стоит одного юниформа. Поэтому тень моста здесь ОДИН слой с честным мягким краем.
|
|
1796
|
+
*/
|
|
1797
|
+
blur?: Interpolated<number>;
|
|
1798
|
+
/**
|
|
1799
|
+
* Уровень полотна в МЕТРАХ — для рельефных вариантов карты: дорожка внутри
|
|
1800
|
+
* приподнятого парка должна лежать на нём, а не тонуть под ним. Меняется
|
|
1801
|
+
* юниформом, геометрия не пересобирается.
|
|
1802
|
+
*/
|
|
1803
|
+
elevation?: Interpolated<number>;
|
|
1804
|
+
/**
|
|
1805
|
+
* ПРИЗРАК: с какой прозрачностью линия просвечивает СКВОЗЬ ЗДАНИЯ (0 — не
|
|
1806
|
+
* просвечивает вовсе). Отдельный проход после объёма и с ПЕРЕВЁРНУТОЙ
|
|
1807
|
+
* проверкой глубины, поэтому в него попадают ровно те куски, что ушли за
|
|
1808
|
+
* дом, — видимые не рисуются дважды и яркость не удваивается. То же, что
|
|
1809
|
+
* `ghostOpacity` у рантайм-объектов: в плотной застройке от ленты пробок
|
|
1810
|
+
* иначе остаются обрывки, и куда идёт улица — непонятно.
|
|
1811
|
+
*/
|
|
1812
|
+
ghostOpacity?: Interpolated<number>;
|
|
1813
|
+
/**
|
|
1814
|
+
* Пунктир: `[штрих, пропуск]` в пикселях. Рисунок идёт непрерывно вдоль
|
|
1815
|
+
* всей линии, а не начинается заново на каждом отрезке.
|
|
1816
|
+
*/
|
|
1817
|
+
/**
|
|
1818
|
+
* Брать ширину ИЗ ДАННЫХ (атрибут width тайла, в метрах), а не из `width` в пикселях.
|
|
1819
|
+
*
|
|
1820
|
+
* Нужно дорогам: у каждой своя ширина, и полотно обязано быть объектом местности. Там, где
|
|
1821
|
+
* атрибута в тайле нет, работает обычная `width` — поэтому флаг безопасно включить заранее.
|
|
1822
|
+
*/
|
|
1823
|
+
widthFromData?: boolean;
|
|
1824
|
+
/**
|
|
1825
|
+
* Прибавка к ширине из данных, ПИКСЕЛИ. Нужна обводке: она обязана быть шире полотна, иначе
|
|
1826
|
+
* при одинаковой ширине из данных её попросту не видно.
|
|
1827
|
+
*/
|
|
1828
|
+
widthExtra?: Interpolated<number>;
|
|
1829
|
+
dashArray?: [number, number];
|
|
1830
|
+
/**
|
|
1831
|
+
* Пунктир В ШИРИНАХ ЛИНИИ — как `line-dasharray` у MapLibre: [штрих, пробел] множителями
|
|
1832
|
+
* текущей ширины. Толще линия — длиннее штрих, поэтому пунктир на любом зуме одинаков по виду.
|
|
1833
|
+
*
|
|
1834
|
+
* Этап (c): любой длины `[штрих, пробел, штрих, …]` и выражением (по зуму — смена рисунка со
|
|
1835
|
+
* смешением, по фиче — свой у фичи), как `line-dasharray` MapLibre. Постоянная пара рисуется
|
|
1836
|
+
* прежним путём шейдера.
|
|
1837
|
+
*/
|
|
1838
|
+
dashWidths?: [number, number] | number[] | unknown[];
|
|
1839
|
+
/**
|
|
1840
|
+
* Зазор посередине линии в пикселях — `line-gap-width` у MapLibre. Ненулевой превращает линию
|
|
1841
|
+
* в «трубу»: две полосы шириной `width` по краям зазора. Так рисуются обводки мостов и тоннелей.
|
|
1842
|
+
*/
|
|
1843
|
+
gapWidth?: Interpolated<number>;
|
|
1844
|
+
/**
|
|
1845
|
+
* Концы и стыки линии — `line-cap`, `line-join`, `line-miter-limit` MapLibre. Без них — прежняя
|
|
1846
|
+
* капсула (скругление везде). Заданные включают свой вариант программы и данные стыков в вершине.
|
|
1847
|
+
*/
|
|
1848
|
+
lineCap?: 'butt' | 'round' | 'square';
|
|
1849
|
+
lineJoin?: 'bevel' | 'round' | 'miter';
|
|
1850
|
+
miterLimit?: number;
|
|
1851
|
+
/**
|
|
1852
|
+
* ШИРИНА В МЕТРАХ вместо пикселей — для РАЗМЕТКИ.
|
|
1853
|
+
*
|
|
1854
|
+
* Полоса разметки это объект местности: по ГОСТ Р 51256 сплошная осевая — 0.1–0.2 м, зебра —
|
|
1855
|
+
* полосы по 0.4 м. В пикселях такую линию задать нельзя: на z16 она была бы вдвое шире, чем
|
|
1856
|
+
* на z17, и на близком зуме вместо разметки получалась бы полоса во всю полосу движения.
|
|
1857
|
+
*
|
|
1858
|
+
* Задана — ширина считается от неё (`width` при этом не смотрится вовсе).
|
|
1859
|
+
*/
|
|
1860
|
+
widthMeters?: Interpolated<number>;
|
|
1861
|
+
/**
|
|
1862
|
+
* СДВИГ ПОПЕРЁК ЛИНИИ В МЕТРАХ — тоже для разметки.
|
|
1863
|
+
*
|
|
1864
|
+
* Полоса лежит не по оси дороги, а на своём месте: осевая по середине, краевая в 3.3 м от неё,
|
|
1865
|
+
* разделительная между полосами. Это размер на земле, и задавать его пикселями нельзя.
|
|
1866
|
+
*/
|
|
1867
|
+
offsetMeters?: Interpolated<number>;
|
|
1868
|
+
/**
|
|
1869
|
+
* Пунктир В МЕТРАХ: `[штрих, пропуск]`.
|
|
1870
|
+
*
|
|
1871
|
+
* У разметки 1.5 штрих и пропуск относятся как 1:3 (3 м и 9 м вне перекрёстка) — и это тоже
|
|
1872
|
+
* размер на земле, а не на экране.
|
|
1873
|
+
*/
|
|
1874
|
+
dashMeters?: [number, number];
|
|
1875
|
+
/**
|
|
1876
|
+
* Стрелки направления (односторонние улицы). Рисуются аналитически
|
|
1877
|
+
* шевронами поверх полотна — без текстуры, поэтому чёткие на любом зуме.
|
|
1878
|
+
*/
|
|
1879
|
+
arrow?: boolean;
|
|
1880
|
+
/**
|
|
1881
|
+
* Каким рисунком показывать направление: `chevron` — «птичка» поверх
|
|
1882
|
+
* полотна (односторонние улицы), `head` — сплошное остриё во всю ширину
|
|
1883
|
+
* ленты (пробки: так это рисует сервер и так же выглядит у Яндекса).
|
|
1884
|
+
*/
|
|
1885
|
+
arrowStyle?: 'chevron' | 'head' | 'headOnly' | 'dash';
|
|
1886
|
+
/**
|
|
1887
|
+
* Просвет между стрелками-штрихами, пиксели (`arrowStyle: 'dash'`). Из него
|
|
1888
|
+
* и `arrowPeriod` выводится длина самой стрелки.
|
|
1889
|
+
*/
|
|
1890
|
+
arrowGap?: Interpolated<number>;
|
|
1891
|
+
/**
|
|
1892
|
+
* Насколько раздуть фигуру стрелки, пиксели. Обводка делается ВТОРЫМ слоем
|
|
1893
|
+
* с тем же набором чисел и ненулевым раздутием: у знакового расстояния это
|
|
1894
|
+
* сдвиг порога, поэтому обводка получается равномерной и со скруглёнными
|
|
1895
|
+
* краями.
|
|
1896
|
+
*/
|
|
1897
|
+
arrowOutline?: Interpolated<number>;
|
|
1898
|
+
/** Полуширина древка стрелки-штриха, пиксели. */
|
|
1899
|
+
arrowShaft?: Interpolated<number>;
|
|
1900
|
+
/** Полуширина головы у основания, пиксели. Больше древка — иначе не стрелка. */
|
|
1901
|
+
arrowHead?: Interpolated<number>;
|
|
1902
|
+
arrowColor?: Interpolated<string>;
|
|
1903
|
+
/** Расстояние между стрелками и их размер, пиксели. */
|
|
1904
|
+
arrowPeriod?: Interpolated<number>;
|
|
1905
|
+
arrowSize?: Interpolated<number>;
|
|
1906
|
+
/** Этап (d): прозрачность слоя ЦЕЛИКОМ (`line-layer-opacity`) — без накопления на перекрытиях. */
|
|
1907
|
+
layerOpacity?: Interpolated<number>;
|
|
1908
|
+
/** Сдвиг линии на экране, пиксели (`line-translate`). */
|
|
1909
|
+
translate?: Interpolated<[number, number]>;
|
|
1910
|
+
/** `map` — сдвиг поворачивается с картой, `viewport` — по экрану (`line-translate-anchor`). */
|
|
1911
|
+
translateAnchor?: 'map' | 'viewport';
|
|
1912
|
+
/**
|
|
1913
|
+
* `line-round-limit`: круглый стык с поворотом положе этого (длина острия в полуширинах)
|
|
1914
|
+
* рисуется острым. Только при `lineJoin: round`; без поля — 1.05, как у MapLibre.
|
|
1915
|
+
*/
|
|
1916
|
+
roundLimit?: number;
|
|
1917
|
+
/** Узор из спрайта вдоль линии (`line-pattern`): имя картинки или выражение. */
|
|
1918
|
+
pattern?: unknown;
|
|
1919
|
+
/**
|
|
1920
|
+
* Этап (x): цвет вдоль линии (`line-gradient`) — выражение от `["line-progress"]`, доли длины
|
|
1921
|
+
* всей линии. Главнее `color`; доли знает только GeoJSON-источник с `lineMetrics: true`.
|
|
1922
|
+
*/
|
|
1923
|
+
gradient?: unknown;
|
|
1924
|
+
};
|
|
1925
|
+
/** Порядок фич внутри слоя (`line-sort-key`): меньший рисуется раньше. Бывает по фиче. */
|
|
1926
|
+
sortKey?: unknown;
|
|
1927
|
+
}
|
|
1928
|
+
interface FillExtrusionLayerSpec extends LayerBase {
|
|
1929
|
+
type: 'fill-extrusion';
|
|
1930
|
+
paint: {
|
|
1931
|
+
/** Цвет стен; `{ from }` — «как у такого-то слоя» (так красятся этажи под цвет дома). */
|
|
1932
|
+
color: Interpolated<string> | ColorFrom;
|
|
1933
|
+
/**
|
|
1934
|
+
* Высота и низ стены в метрах — как `fill-extrusion-height/base` у MapLibre: число или
|
|
1935
|
+
* выражение по фиче. Не заданы — берутся из свойств тайла (`render_height`, `height`, этажи).
|
|
1936
|
+
*/
|
|
1937
|
+
height?: unknown;
|
|
1938
|
+
base?: unknown;
|
|
1939
|
+
roofColor?: Interpolated<string>;
|
|
1940
|
+
opacity?: Interpolated<number>;
|
|
1941
|
+
/** Затенение у основания, 0..1. */
|
|
1942
|
+
aoStrength?: Interpolated<number>;
|
|
1943
|
+
/** Разброс оттенка между зданиями, 0..1 — чтобы квартал не был однотонным. */
|
|
1944
|
+
tintVariation?: Interpolated<number>;
|
|
1945
|
+
/**
|
|
1946
|
+
* Рисунок фасада и кровли, 0..1. Ноль — гладкие стены (так выглядели здания
|
|
1947
|
+
* до появления фасадов), единица — окна, швы и фальцы. Считается процедурно,
|
|
1948
|
+
* текстур не требует и на мелких зумах гасится сам.
|
|
1949
|
+
*/
|
|
1950
|
+
facadeDetail?: Interpolated<number>;
|
|
1951
|
+
/** Цвет остекления. */
|
|
1952
|
+
windowColor?: Interpolated<string>;
|
|
1953
|
+
/** Цвет переплёта и откосов. */
|
|
1954
|
+
windowFrameColor?: Interpolated<string>;
|
|
1955
|
+
/**
|
|
1956
|
+
* Разброс тона и градиента стекла, 0..1 (по умолчанию 1).
|
|
1957
|
+
*
|
|
1958
|
+
* Свой тон у каждого окна и отражение неба по высоте дают фасаду вторую фактуру. На синем
|
|
1959
|
+
* остеклении это жизнь, а на стекле в тон стене — пятна: часть окон темнее стены, часть
|
|
1960
|
+
* светлее. Ноль оставляет ровно середину.
|
|
1961
|
+
*/
|
|
1962
|
+
windowVariation?: Interpolated<number>;
|
|
1963
|
+
/**
|
|
1964
|
+
* Сила швов на стенах и кровлях, 0..1 (по умолчанию 1).
|
|
1965
|
+
*
|
|
1966
|
+
* Швы делают дом сборным. Но там, где стена и стекло одного тона, они остаются единственным
|
|
1967
|
+
* контрастом на фасаде, и дом читается сеткой линий, а не объёмом.
|
|
1968
|
+
*/
|
|
1969
|
+
seamStrength?: Interpolated<number>;
|
|
1970
|
+
/**
|
|
1971
|
+
* ЛЁД, 0..1. Ноль — обычный матовый дом.
|
|
1972
|
+
*
|
|
1973
|
+
* Настоящий лёд выдают две вещи, и обе видно на 3D-домах Baidu: кромка светится тем сильнее,
|
|
1974
|
+
* чем острее угол взгляда к грани (у стекла и льда так отражается небо), и низ стены светлее
|
|
1975
|
+
* верха — свет уходит в толщу и рассеивается. Ни то, ни другое не задать цветом: это зависит
|
|
1976
|
+
* от камеры и от высоты точки, то есть считается в шейдере.
|
|
1977
|
+
*
|
|
1978
|
+
* Цвет при этом остаётся за темой: ручка только добавляет блик и градиент поверх него.
|
|
1979
|
+
*/
|
|
1980
|
+
ice?: Interpolated<number>;
|
|
1981
|
+
/**
|
|
1982
|
+
* ОТРАЖЕНИЕ ДОМОВ В СТЕКЛЯННОЙ ЗЕМЛЕ, 0..1 — сила зеркала. Ноль — отражения нет.
|
|
1983
|
+
*
|
|
1984
|
+
* Работает только с z18 (`REFLECTION_MIN_ZOOM` в `layers/renderer`) и без рельефа: это второй
|
|
1985
|
+
* проход по всем домам кадра, и на общем плане он удвоил бы самую дорогую геометрию.
|
|
1986
|
+
*/
|
|
1987
|
+
reflection?: Interpolated<number>;
|
|
1988
|
+
/**
|
|
1989
|
+
* БЛЕСК СТЕКЛЯННОЙ ЗЕМЛИ, 0..1: отражение неба по Френелю — чем дальше и чем более скользящий
|
|
1990
|
+
* взгляд, тем сильнее земля берёт цвет горизонта. Работает на любом зуме (это один квад), в
|
|
1991
|
+
* отличие от отражения домов.
|
|
1992
|
+
*/
|
|
1993
|
+
reflectionGloss?: Interpolated<number>;
|
|
1994
|
+
/**
|
|
1995
|
+
* ДОМ КАК СТЕКЛО (по образцу Baidu) — только вместе с `ice`.
|
|
1996
|
+
*
|
|
1997
|
+
* `glassTint` — цвет стекла у земли (у Baidu бирюзовый), `glassTintAmount` — насколько (0..1),
|
|
1998
|
+
* `glassTintHeight` — на какой высоте, метры, цвет растворяется: низ цветной, верх светлый, как
|
|
1999
|
+
* у Baidu. Кровля светлее всего — оттенка на ней одна десятая. `glassRim` — светлая
|
|
2000
|
+
* кромка по Френелю: грань, повёрнутая к взгляду ребром, светится, как край стекла.
|
|
2001
|
+
*/
|
|
2002
|
+
glassTint?: Interpolated<string>;
|
|
2003
|
+
glassTintAmount?: Interpolated<number>;
|
|
2004
|
+
glassTintHeight?: Interpolated<number>;
|
|
2005
|
+
glassRim?: Interpolated<number>;
|
|
2006
|
+
/**
|
|
2007
|
+
* Насколько верх дома ярче низа, 0..1 — в СВОЁМ цвете, без подмеса белого (0.1 — на 10 %).
|
|
2008
|
+
* Кровля — наравне с верхом стены. Только с `glassTintAmount`.
|
|
2009
|
+
*/
|
|
2010
|
+
glassTopLight?: Interpolated<number>;
|
|
2011
|
+
/**
|
|
2012
|
+
* Градиент по плоской крыше, 0..1: ближний к камере край — в тон стекла, дальний — светлый.
|
|
2013
|
+
* Чтобы крыши стеклянного квартала не сливались в одно поле. Только с `glassTintAmount`.
|
|
2014
|
+
*/
|
|
2015
|
+
glassRoofGradient?: Interpolated<number>;
|
|
2016
|
+
/**
|
|
2017
|
+
* Доля светящихся окон, 0..1 — для ночных тем. Какие именно окна горят,
|
|
2018
|
+
* решает хеш ячейки, поэтому при движении камеры свет не «бегает».
|
|
2019
|
+
*/
|
|
2020
|
+
windowGlow?: Interpolated<number>;
|
|
2021
|
+
/** Высота этажа в метрах: шаг сетки окон. */
|
|
2022
|
+
floorHeight?: Interpolated<number>;
|
|
2023
|
+
/**
|
|
2024
|
+
* На сколько метров стекло утоплено от плоскости стены (по умолчанию 0.18).
|
|
2025
|
+
* Край проёма кладёт на утопленное стекло тень со стороны, где нет солнца, —
|
|
2026
|
+
* именно она и читается как глубина. Ноль возвращает плоское окно.
|
|
2027
|
+
*/
|
|
2028
|
+
windowRecess?: Interpolated<number>;
|
|
2029
|
+
/** Глубина тени откоса, 0..1. */
|
|
2030
|
+
windowRecessShade?: Interpolated<number>;
|
|
2031
|
+
/**
|
|
2032
|
+
* Высота в метрах, на которой цокольное затемнение сходит на нет (по умолчанию 4).
|
|
2033
|
+
* Затемнение считается для ВСЕЙ стены, включая скруглённые углы и фронтоны.
|
|
2034
|
+
*/
|
|
2035
|
+
plinthHeight?: Interpolated<number>;
|
|
2036
|
+
/** Сила цокольного затемнения у самой земли, 0..1. */
|
|
2037
|
+
plinthShade?: Interpolated<number>;
|
|
2038
|
+
/**
|
|
2039
|
+
* Разброс цвета СКАТНЫХ кровель, 0..1. Тон берётся из хеша здания, яркость
|
|
2040
|
+
* остаётся от темы — иначе терракота всплыла бы посреди ночной карты.
|
|
2041
|
+
*/
|
|
2042
|
+
roofVariation?: Interpolated<number>;
|
|
2043
|
+
/** Множитель высоты (например, 0 — «сложить» здания). */
|
|
2044
|
+
heightScale?: Interpolated<number>;
|
|
2045
|
+
/**
|
|
2046
|
+
* Градиент стены по высоте — `fill-extrusion-vertical-gradient` MapLibre. Работает только со
|
|
2047
|
+
* светом MapLibre (`lighting: 'maplibre'`); не задан — включён, как и у MapLibre.
|
|
2048
|
+
*/
|
|
2049
|
+
verticalGradient?: boolean;
|
|
2050
|
+
/** Сдвиг объёма по земле, пиксели экрана (`fill-extrusion-translate`). */
|
|
2051
|
+
translate?: Interpolated<[number, number]>;
|
|
2052
|
+
/** `map` — сдвиг поворачивается с картой, `viewport` — по экрану. */
|
|
2053
|
+
translateAnchor?: 'map' | 'viewport';
|
|
2054
|
+
/** Узор из спрайта на стенах и крыше (`fill-extrusion-pattern`). */
|
|
2055
|
+
pattern?: unknown;
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Подписи и иконки.
|
|
2060
|
+
*
|
|
2061
|
+
* Иконка и текст рисуются ОДНОЙ программой из одного SDF-атласа, поэтому
|
|
2062
|
+
* `color`/`haloColor` применяются к ним одинаково. Цена этого решения —
|
|
2063
|
+
* иконки силуэтные (одноцветные): раскрасить пиктограмму в несколько цветов
|
|
2064
|
+
* таким способом нельзя.
|
|
2065
|
+
*/
|
|
2066
|
+
/** Якорь подписи или значка — какая точка бокса стоит на объекте (`text-anchor` у MapLibre). */
|
|
2067
|
+
type SymbolAnchor = 'center' | 'left' | 'right' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
2068
|
+
interface SymbolLayerSpec extends LayerBase {
|
|
2069
|
+
type: 'symbol';
|
|
2070
|
+
layout?: {
|
|
2071
|
+
/** Шаблон подписи `"{name}"` либо список запасных: первый непустой побеждает. */
|
|
2072
|
+
textField?: string | string[];
|
|
2073
|
+
/** Шаблон имени иконки, например `"{class}"`. */
|
|
2074
|
+
iconImage?: string | string[];
|
|
2075
|
+
/** Кегль подписи в CSS-пикселях. */
|
|
2076
|
+
textSize?: Interpolated<number>;
|
|
2077
|
+
/**
|
|
2078
|
+
* Сокращать родовое слово в названии: «улица Истаравшан» → «ул. Истаравшан».
|
|
2079
|
+
*
|
|
2080
|
+
* Для подписи вдоль дороги это не косметика, а вопрос «поместится или нет»: родовое слово
|
|
2081
|
+
* занимает до половины строки. Так подписывают улицы Яндекс и 2ГИС — см. `text/abbreviate`.
|
|
2082
|
+
*/
|
|
2083
|
+
abbreviate?: boolean;
|
|
2084
|
+
/**
|
|
2085
|
+
* Регистр подписи — как `text-transform` у MapLibre. Меняется в воркере вместе с сокращением:
|
|
2086
|
+
* под этот текст раскладка и ищет место.
|
|
2087
|
+
*/
|
|
2088
|
+
textTransform?: 'none' | 'uppercase' | 'lowercase' | unknown[];
|
|
2089
|
+
/**
|
|
2090
|
+
* Гарнитура подписи — имя набора глифов на сервере шрифтов, как `text-font` у MapLibre
|
|
2091
|
+
* (`Noto Sans Bold`). Не задана — общий шрифт карты (`Noto Sans Regular`).
|
|
2092
|
+
*/
|
|
2093
|
+
textFont?: string;
|
|
2094
|
+
/**
|
|
2095
|
+
* Разрядка букв в долях кегля — как `text-letter-spacing` у Mapbox.
|
|
2096
|
+
*
|
|
2097
|
+
* Не задана — считается от толщины обводки: та раздувает каждую букву в сторону соседней, и без
|
|
2098
|
+
* разрядки плотное слово читается слипшимся пятном (см. `letterSpacingFor`).
|
|
2099
|
+
*/
|
|
2100
|
+
letterSpacing?: Interpolated<number>;
|
|
2101
|
+
/** Размер иконки в CSS-пикселях. */
|
|
2102
|
+
iconSize?: Interpolated<number>;
|
|
2103
|
+
/**
|
|
2104
|
+
* Зазор между иконкой и текстом в пикселях — по горизонтали при боковой
|
|
2105
|
+
* раскладке, по вертикали при верхней. Задаётся на слой: у значка над
|
|
2106
|
+
* подписью уместен зазор в пару пикселей, у бокового — заметно больше.
|
|
2107
|
+
*/
|
|
2108
|
+
iconTextGap?: number;
|
|
2109
|
+
/**
|
|
2110
|
+
* Где стоит иконка относительно подписи: `top` — над ней по центру (так у
|
|
2111
|
+
* Mapbox Standard и у Яндекса: значок ровно над точкой объекта), `left` и
|
|
2112
|
+
* `right` — сбоку, плотнее по вертикали, `behind` — плашка под подписью.
|
|
2113
|
+
*
|
|
2114
|
+
* `auto` — ПЕРЕБОР сторон: подпись справа от значка, занято — слева, занято — под ним. Так
|
|
2115
|
+
* подписей на плотной карте помещается заметно больше: подпись, которой не нашлось места с
|
|
2116
|
+
* одной стороны, находит его с другой вместо того, чтобы пропасть. Работает только с
|
|
2117
|
+
* `iconFrame: 'pin'` — значок при этом остаётся остриём на объекте.
|
|
2118
|
+
*/
|
|
2119
|
+
iconPlacement?: 'top' | 'left' | 'right' | 'behind' | 'auto';
|
|
2120
|
+
/**
|
|
2121
|
+
* Как ставится подпись: `point` — горизонтально у точки привязки (по
|
|
2122
|
+
* умолчанию), `line` — вдоль линии объекта, изгибаясь по ней.
|
|
2123
|
+
*
|
|
2124
|
+
* Вдоль линии подпись читается как часть дороги, а не как ярлык рядом с
|
|
2125
|
+
* ней; так подписаны улицы во всех больших картах. Значка при таком
|
|
2126
|
+
* размещении нет: он не поворачивается вместе с текстом и выглядел бы
|
|
2127
|
+
* приклеенным сбоку.
|
|
2128
|
+
*/
|
|
2129
|
+
textPlacement?: 'point' | 'line';
|
|
2130
|
+
/**
|
|
2131
|
+
* Как подпись вдоль линии стоит относительно наклона карты.
|
|
2132
|
+
*
|
|
2133
|
+
* `viewport` (по умолчанию) — буквы обращены к экрану и при наклоне не сжимаются: читается
|
|
2134
|
+
* лучше всего. `map` — буквы ЛЕЖАТ НА ДОРОГЕ и в наклоне сжимаются в перспективе вместе с ней,
|
|
2135
|
+
* как `text-pitch-alignment: map` у MapLibre (у `symbol-placement: line` это его умолчание).
|
|
2136
|
+
* Только для `textPlacement: 'line'`.
|
|
2137
|
+
*/
|
|
2138
|
+
textPitchAlignment?: 'viewport' | 'map';
|
|
2139
|
+
/**
|
|
2140
|
+
* Шаг повторения подписи вдоль линии, экранные пиксели (`textPlacement:
|
|
2141
|
+
* 'line'`). По умолчанию 250 — как `symbol-spacing` у Mapbox.
|
|
2142
|
+
*
|
|
2143
|
+
* Длинная улица подписывается несколько раз: название, поставленное один
|
|
2144
|
+
* раз, находится только в одном месте, и на соседнем экране та же улица
|
|
2145
|
+
* снова безымянная. Ноль — ставить ровно один раз.
|
|
2146
|
+
*/
|
|
2147
|
+
symbolSpacing?: Interpolated<number>;
|
|
2148
|
+
/** Смещение подписи от точки привязки, CSS-пиксели. */
|
|
2149
|
+
offset?: [number, number];
|
|
2150
|
+
/** Максимум символов в строке до переноса. */
|
|
2151
|
+
maxLineChars?: number;
|
|
2152
|
+
/**
|
|
2153
|
+
* РАСКЛАДКА ПО ЯКОРЯМ, КАК У MapLibre. Заданный `textAnchor` или `iconAnchor` включает её вместо
|
|
2154
|
+
* нашей блочной (`iconPlacement`): значок и подпись ставятся НЕЗАВИСИМО — каждый своим якорем к
|
|
2155
|
+
* точке объекта, подпись ещё и со смещением `textOffset` в em (кеглях). Так устроены все стили
|
|
2156
|
+
* MapLibre: значок POI стоит центром на объекте, подпись — верхним краем под ним.
|
|
2157
|
+
*/
|
|
2158
|
+
textAnchor?: SymbolAnchor | unknown[];
|
|
2159
|
+
/** Смещение подписи от точки в em (× `textSize`), `text-offset` у MapLibre. */
|
|
2160
|
+
textOffset?: [number, number] | unknown[];
|
|
2161
|
+
iconAnchor?: SymbolAnchor | unknown[];
|
|
2162
|
+
/**
|
|
2163
|
+
* ── РАСКЛАДКА MapLibre (`placementMode: maplibre`), этап b формата v2 ──
|
|
2164
|
+
* Поля ниже читает только раскладка по якорям; у блочной раскладки свои правила.
|
|
2165
|
+
*/
|
|
2166
|
+
/** Смещение значка в пикселях значка (× `icon-size`), `icon-offset`. */
|
|
2167
|
+
iconOffset?: [number, number] | unknown[];
|
|
2168
|
+
/** Поворот подписи в градусах по часовой, `text-rotate`. */
|
|
2169
|
+
textRotate?: Interpolated<number>;
|
|
2170
|
+
/** Межстрочный интервал в em, `text-line-height` (по умолчанию 1.2). */
|
|
2171
|
+
textLineHeight?: Interpolated<number>;
|
|
2172
|
+
/** Выравнивание строк многострочной подписи, `text-justify`; `auto` — по якорю. */
|
|
2173
|
+
textJustify?: 'auto' | 'left' | 'center' | 'right' | unknown[];
|
|
2174
|
+
/** Якоря-кандидаты: перебираются по порядку, пока подпись не встанет, `text-variable-anchor`. */
|
|
2175
|
+
textVariableAnchor?: SymbolAnchor[];
|
|
2176
|
+
/** Якоря-кандидаты со своими смещениями (em): `[якорь, [x, y], якорь, [x, y], …]`, `text-variable-anchor-offset`. */
|
|
2177
|
+
textVariableAnchorOffset?: unknown[];
|
|
2178
|
+
/** Смещение подписи от точки по радиусу в em при переборе якорей, `text-radial-offset`. */
|
|
2179
|
+
textRadialOffset?: Interpolated<number>;
|
|
2180
|
+
/** Значок растягивается под подпись, `icon-text-fit`. */
|
|
2181
|
+
iconTextFit?: 'none' | 'width' | 'height' | 'both';
|
|
2182
|
+
/** Поля вокруг подписи при растяжке значка, пиксели `[верх, право, низ, лево]`, `icon-text-fit-padding`. */
|
|
2183
|
+
iconTextFitPadding?: [number, number, number, number];
|
|
2184
|
+
/** Перекрытие значка отдельно от подписи, `icon-allow-overlap` (без поля — как `allowOverlap`). */
|
|
2185
|
+
iconAllowOverlap?: boolean;
|
|
2186
|
+
/** Значок не занимает места отдельно от подписи, `icon-ignore-placement` (без поля — как `ignorePlacement`). */
|
|
2187
|
+
iconIgnorePlacement?: boolean;
|
|
2188
|
+
/**
|
|
2189
|
+
* Этап (z): `text-overlap: cooperative` — подпись встаёт поверх `always` и других `cooperative`,
|
|
2190
|
+
* но не поверх `never`. `always`/`never` — по-прежнему `allowOverlap`. Только раскладка MapLibre.
|
|
2191
|
+
*/
|
|
2192
|
+
textOverlap?: 'cooperative';
|
|
2193
|
+
/** То же для значка, `icon-overlap: cooperative`. */
|
|
2194
|
+
iconOverlap?: 'cooperative';
|
|
2195
|
+
/**
|
|
2196
|
+
* Этап (z): режимы набора по порядку (`text-writing-mode`): `vertical` ставит столбцом подпись со
|
|
2197
|
+
* знаками «прямой» ориентации (иероглифы), `horizontal` — строкой. Только точка раскладки MapLibre.
|
|
2198
|
+
*/
|
|
2199
|
+
textWritingMode?: ('horizontal' | 'vertical')[];
|
|
2200
|
+
/** Подпись необязательна: не встала — значок остаётся один, `text-optional`. */
|
|
2201
|
+
textOptional?: boolean;
|
|
2202
|
+
/** Значок необязателен: не встал — подпись остаётся одна, `icon-optional`. */
|
|
2203
|
+
iconOptional?: boolean;
|
|
2204
|
+
/** Поле вокруг бокса подписи, пиксели, `text-padding` (по умолчанию 2). */
|
|
2205
|
+
textPadding?: Interpolated<number>;
|
|
2206
|
+
/** Поле вокруг бокса значка, пиксели: число или `[верх, право, низ, лево]` CSS, `icon-padding`. */
|
|
2207
|
+
iconPadding?: number | number[] | unknown[];
|
|
2208
|
+
/** Порядок раскладки внутри слоя: меньший ключ ставится раньше и рисуется ниже, `symbol-sort-key`. */
|
|
2209
|
+
symbolSortKey?: Interpolated<number>;
|
|
2210
|
+
/** Порядок наложения внутри слоя, `symbol-z-order`. */
|
|
2211
|
+
symbolZOrder?: 'auto' | 'viewport-y' | 'source';
|
|
2212
|
+
/**
|
|
2213
|
+
* Этап (x): высота точечного символа над опорой, метры (`symbol-height-offset`); по зуму и по фиче.
|
|
2214
|
+
* Только раскладка MapLibre и только у точки (вдоль линии — не действует, как у MapLibre).
|
|
2215
|
+
*/
|
|
2216
|
+
symbolHeightOffset?: unknown;
|
|
2217
|
+
/** От чего мерить высоту: `ground` — от рельефа под символом, `absolute` — от нуля (`symbol-height-anchor`). */
|
|
2218
|
+
symbolHeightAnchor?: 'ground' | 'absolute';
|
|
2219
|
+
/** Поворот подписи у точки: `map` — вместе с картой, `viewport`/`auto` — к экрану, `text-rotation-alignment`. */
|
|
2220
|
+
textRotationAlignment?: 'auto' | 'map' | 'viewport' | 'viewport-glyph';
|
|
2221
|
+
/** То же для значка у точки, `icon-rotation-alignment`. */
|
|
2222
|
+
iconRotationAlignment?: 'auto' | 'map' | 'viewport';
|
|
2223
|
+
/** Подпись «по карте» не переворачивается вверх ногами, `text-keep-upright` (по умолчанию да). */
|
|
2224
|
+
textKeepUpright?: boolean;
|
|
2225
|
+
/** Этап (z): значок вдоль линии, повёрнутый по ней, разворачивается «головой вверх», `icon-keep-upright` (по умолчанию нет). */
|
|
2226
|
+
iconKeepUpright?: boolean;
|
|
2227
|
+
/**
|
|
2228
|
+
* Размер значка МНОЖИТЕЛЕМ его натурального размера — `icon-size` у MapLibre. Натуральный —
|
|
2229
|
+
* размер картинки спрайта в CSS-пикселях (пиксели / `pixelRatio`). Задан — `iconSize` не читается.
|
|
2230
|
+
*/
|
|
2231
|
+
iconScale?: Interpolated<number>;
|
|
2232
|
+
/** Перенос строк по ширине в em — `text-max-width` у MapLibre (по умолчанию у них 10). */
|
|
2233
|
+
textMaxWidth?: Interpolated<number>;
|
|
2234
|
+
/**
|
|
2235
|
+
* Вдоль линии (`textPlacement: 'line'`) подпись ставится НЕ изгибом по дороге, а горизонтально
|
|
2236
|
+
* в узлах сетки — как щит трассы у MapLibre (`text-rotation-alignment: viewport`).
|
|
2237
|
+
*/
|
|
2238
|
+
lineUpright?: boolean;
|
|
2239
|
+
/** Значок вдоль линии повёрнут по дороге (`icon-rotation-alignment: map`) — стрелка односторонней. */
|
|
2240
|
+
iconAlongLine?: boolean;
|
|
2241
|
+
/**
|
|
2242
|
+
* Значок ЛЕЖИТ на карте (`icon-pitch-alignment: map`): при наклоне сплющивается вместе с землёй.
|
|
2243
|
+
* Пока — у значков вдоль линии без подписи (стрелки направления).
|
|
2244
|
+
*/
|
|
2245
|
+
iconPitchAlignment?: 'map' | 'viewport';
|
|
2246
|
+
/**
|
|
2247
|
+
* Места вдоль линии (`textPlacement: 'line'`, значки и подписи «стоя») — по алгоритму MapLibre:
|
|
2248
|
+
* в координатах тайла, с переувеличением и срезом по тайлу (`text/maplibre-anchors.ts`). Без поля —
|
|
2249
|
+
* наша сетка по земле. Ставит импортёр стилей MapLibre.
|
|
2250
|
+
*/
|
|
2251
|
+
lineAnchors?: 'maplibre';
|
|
2252
|
+
/**
|
|
2253
|
+
* Раскладка коллизий КАК У MapLibre: порядок — верхний слой первым, тайлы по их правилу, внутри
|
|
2254
|
+
* тайла по порядку символов, без надбавки «уже стоявшим»; подпись вдоль линии занимает место
|
|
2255
|
+
* цепочкой кругов. Ставит импортёр стилей MapLibre.
|
|
2256
|
+
*/
|
|
2257
|
+
placementMode?: 'maplibre';
|
|
2258
|
+
/** Одно место в середине линии (`symbol-placement: line-center`); только с `lineAnchors`. */
|
|
2259
|
+
lineCenter?: boolean;
|
|
2260
|
+
/** Наибольший излом под подписью вдоль линии, градусы (`text-max-angle`, по умолчанию 45). */
|
|
2261
|
+
textMaxAngle?: Interpolated<number>;
|
|
2262
|
+
/**
|
|
2263
|
+
* Что делать с незнакомым именем значка: `dot` (по умолчанию) — нейтральная точка, чтобы объект
|
|
2264
|
+
* не пропал; `skip` — не рисовать значок вовсе, как MapLibre (подпись при этом остаётся).
|
|
2265
|
+
*/
|
|
2266
|
+
iconMissing?: 'dot' | 'skip';
|
|
2267
|
+
/** Значок — из встроенного набора движка, даже при `iconMissing: 'skip'` (круги слоя `circle`). */
|
|
2268
|
+
iconBuiltin?: boolean;
|
|
2269
|
+
/** Не участвовать в коллизиях (подпись всегда видна). */
|
|
2270
|
+
allowOverlap?: boolean;
|
|
2271
|
+
/**
|
|
2272
|
+
* НЕ ЗАНИМАТЬ МЕСТА У ОСТАЛЬНЫХ, но самому уступать занятому.
|
|
2273
|
+
*
|
|
2274
|
+
* Половина `allowOverlap`, как `icon-ignore-placement` у Mapbox. Нужна фоновым подписям —
|
|
2275
|
+
* названиям улиц и номерам домов: они рисуются там, где свободно, но не вытесняют собой
|
|
2276
|
+
* значки и названия мест. Без этого на плотной застройке номера домов съедают POI, а их
|
|
2277
|
+
* самих никто не читает.
|
|
2278
|
+
*/
|
|
2279
|
+
ignorePlacement?: boolean;
|
|
2280
|
+
/**
|
|
2281
|
+
* ГРУППА РАСКЛАДКИ: с кем подпись всё-таки делит место.
|
|
2282
|
+
*
|
|
2283
|
+
* Работает в паре с `ignorePlacement`. Сам по себе он снимает подпись с учёта полностью — и
|
|
2284
|
+
* тогда названия улиц ложатся поверх номеров домов и друг друга: каждая уступает значкам, но
|
|
2285
|
+
* ни одна не знает о соседке. Общая группа возвращает их в коллизии между собой, оставляя
|
|
2286
|
+
* невидимыми для всех остальных слоёв.
|
|
2287
|
+
*
|
|
2288
|
+
* Значение — любая строка, важно лишь совпадение: слои с одной строкой расталкивают друг
|
|
2289
|
+
* друга, с разными — не видят.
|
|
2290
|
+
*/
|
|
2291
|
+
placementGroup?: string;
|
|
2292
|
+
/**
|
|
2293
|
+
* Дополнительное поле вокруг подписи в пикселях — разрежает однотипные
|
|
2294
|
+
* метки. Номер трассы иначе повторяется на каждом отрезке: перекрытия нет,
|
|
2295
|
+
* а на карте это рябь из одинаковых плашек.
|
|
2296
|
+
*/
|
|
2297
|
+
collisionPadding?: number;
|
|
2298
|
+
/** Добавка к приоритету слоя при коллизиях. */
|
|
2299
|
+
priority?: number;
|
|
2300
|
+
/**
|
|
2301
|
+
* Круглая подложка под значком — как у Яндекса и в Mapbox Standard: значок
|
|
2302
|
+
* стоит на кружке фона с тонкой рамкой и читается на любой заливке, а не
|
|
2303
|
+
* только на светлой земле.
|
|
2304
|
+
*
|
|
2305
|
+
* Это ОТДЕЛЬНЫЙ значок под иконкой, а не обводка: обводка у нас общая с
|
|
2306
|
+
* текстом (одна программа), и «жирный контур» вокруг пиктограммы выглядит
|
|
2307
|
+
* грязно, а кружок — фигура со своей заливкой и своей рамкой.
|
|
2308
|
+
*
|
|
2309
|
+
* `pin` — та же подложка, но с остриём вниз. Отличие не в рисунке, а в ТОЧКЕ ПРИВЯЗКИ: у
|
|
2310
|
+
* кружка на объекте стоит его середина, у булавки — остриё. Поэтому с булавкой подпись можно
|
|
2311
|
+
* увести вбок (`iconPlacement: 'left'`), не теряя, к чему она относится: показывает не значок
|
|
2312
|
+
* целиком, а его кончик. Так устроены POI у Baidu Maps.
|
|
2313
|
+
*/
|
|
2314
|
+
iconFrame?: 'circle' | 'pin' | 'none';
|
|
2315
|
+
/** Диаметр подложки относительно значка. */
|
|
2316
|
+
iconFrameScale?: number;
|
|
2317
|
+
/**
|
|
2318
|
+
* СОСТАВНОЙ ЗНАЧОК: силуэты, нарисованные один поверх другого в одной точке.
|
|
2319
|
+
*
|
|
2320
|
+
* Атлас значков у нас общий с буквами и одноканальный — из него приходит форма, а цвет
|
|
2321
|
+
* ставится на весь поток вершин сразу. Разноцветной пиктограммы одной картинкой поэтому не
|
|
2322
|
+
* получится, и она собирается из частей: у светофора это корпус, три лампы и мачта. Части
|
|
2323
|
+
* перечисляются СНИЗУ ВВЕРХ (первая ложится под остальные), цвета им раздаёт
|
|
2324
|
+
* `paint.partColors`, обводку — `paint.partHaloWidths`.
|
|
2325
|
+
*
|
|
2326
|
+
* Совмещать части координатами не нужно: у них общий viewBox, поэтому и общий растр, и
|
|
2327
|
+
* рисуются они в один и тот же прямоугольник. Сам `iconImage` при этом обязателен — по нему
|
|
2328
|
+
* считается размер и место в коллизиях, и он же остаётся одноцветным запасным вариантом, пока
|
|
2329
|
+
* части не догрузились.
|
|
2330
|
+
*/
|
|
2331
|
+
iconParts?: string[];
|
|
2332
|
+
/**
|
|
2333
|
+
* Свойство фичи с поворотом значка в градусах (0 — север, по часовой).
|
|
2334
|
+
* Значок доворачивается на поворот камеры, поэтому стрелка у входа смотрит
|
|
2335
|
+
* внутрь дома при любом развороте карты.
|
|
2336
|
+
*/
|
|
2337
|
+
iconRotate?: string | number | unknown[];
|
|
2338
|
+
/**
|
|
2339
|
+
* Показывать слой ТОЛЬКО у выбранного здания (`highlight`).
|
|
2340
|
+
*
|
|
2341
|
+
* Так устроены входы: висеть у каждого дома они не должны — это шум, а при
|
|
2342
|
+
* выборе дома нужны сразу. Привязка геометрическая, по контуру выбранного
|
|
2343
|
+
* здания: id зданий в тайлах и id в базе живут в РАЗНЫХ пространствах
|
|
2344
|
+
* (тайлы собраны планетайлером, правки — своей схемой), складывать их по id
|
|
2345
|
+
* нечем.
|
|
2346
|
+
*/
|
|
2347
|
+
showFor?: 'highlight';
|
|
2348
|
+
/**
|
|
2349
|
+
* Где живёт значок: `screen` (по умолчанию) — лицом к пользователю, как
|
|
2350
|
+
* обычная подпись; `map` — НА ПОВЕРХНОСТИ карты.
|
|
2351
|
+
*
|
|
2352
|
+
* У `map` значок рисуется не картинкой из атласа, а геометрией на земле:
|
|
2353
|
+
* стрелка входа поворачивается вместе с картой, уходит в перспективу при
|
|
2354
|
+
* наклоне и прячется за домом, который стоит перед ней. Так это выглядит у
|
|
2355
|
+
* Яндекса, и иначе она не читается как «зайти отсюда». Подпись (номер
|
|
2356
|
+
* подъезда) при этом остаётся экранной — её надо читать при любом наклоне.
|
|
2357
|
+
*/
|
|
2358
|
+
placement?: 'screen' | 'map';
|
|
2359
|
+
/**
|
|
2360
|
+
* В чём заданы размеры стрелки: `pixels` (по умолчанию) — в ЭКРАННЫХ
|
|
2361
|
+
* пикселях, `meters` — в метрах на местности.
|
|
2362
|
+
*
|
|
2363
|
+
* Пиксели нужны, чтобы размер не менялся с зумом. Метры на земле означают
|
|
2364
|
+
* рост вдвое на каждый уровень: между z17 и z22 стрелка вырастала с двух
|
|
2365
|
+
* десятков пикселей до трёхсот. Стопы по зуму это лечат лишь отчасти —
|
|
2366
|
+
* интерполяция между ними ЛИНЕЙНАЯ, а масштаб растёт экспоненциально, и
|
|
2367
|
+
* внутри каждого шага размер всё равно вспухает. Так же устроена ширина
|
|
2368
|
+
* линий: она задана в пикселях, а в единицы геометрии переводится в шейдере.
|
|
2369
|
+
*/
|
|
2370
|
+
arrowUnits?: 'pixels' | 'meters';
|
|
2371
|
+
/** Длина стрелки (единицы — по `arrowUnits`). */
|
|
2372
|
+
arrowLength?: Interpolated<number>;
|
|
2373
|
+
/** Ширина древка. */
|
|
2374
|
+
arrowWidth?: Interpolated<number>;
|
|
2375
|
+
/** Толщина обводки. 0 — без обводки. */
|
|
2376
|
+
arrowOutline?: Interpolated<number>;
|
|
2377
|
+
/**
|
|
2378
|
+
* Радиус кружка НА САМОЙ двери. Стрелка показывает, откуда заходить, точка —
|
|
2379
|
+
* куда именно; так это устроено у Яндекса. 0 — без точки.
|
|
2380
|
+
*/
|
|
2381
|
+
arrowDotRadius?: Interpolated<number>;
|
|
2382
|
+
/**
|
|
2383
|
+
* Отступ точки от стены. Дом рисуется следующим проходом с честной глубиной,
|
|
2384
|
+
* и стена перекрывает всё, что лежит у её основания: без отступа точка
|
|
2385
|
+
* пропадает под домом на любом наклоне.
|
|
2386
|
+
*/
|
|
2387
|
+
arrowDotGap?: Interpolated<number>;
|
|
2388
|
+
/**
|
|
2389
|
+
* Отступ остриё↔стена. Стрелка не упирается в дом, а стоит перед ним:
|
|
2390
|
+
* впритык остриё сливается со стеной, а под наклоном ещё и уходит под неё.
|
|
2391
|
+
*/
|
|
2392
|
+
arrowGap?: Interpolated<number>;
|
|
2393
|
+
};
|
|
2394
|
+
paint: {
|
|
2395
|
+
/**
|
|
2396
|
+
* Цвет подписи; `{ from }` — «как у такого-то слоя» (см. `ColorFrom`).
|
|
2397
|
+
*
|
|
2398
|
+
* Ссылка тут нужна ровно затем же, зачем обводке моста: тем два десятка, и слой, отколотый от
|
|
2399
|
+
* существующего (мелкие населённые пункты от крупных), в каждой из них пришлось бы красить
|
|
2400
|
+
* заново. Своего хекса у такого слоя нет — у него есть «как у родителя», и ссылка это и говорит.
|
|
2401
|
+
* Берётся ОДНОИМЁННОЕ свойство: `haloColor: { from: 'place-label' }` — это обводка того слоя.
|
|
2402
|
+
*/
|
|
2403
|
+
color: Interpolated<string> | ColorFrom;
|
|
2404
|
+
haloColor?: Interpolated<string> | ColorFrom;
|
|
2405
|
+
/** Толщина обводки в CSS-пикселях. Обводка обязательна поверх пёстрой карты. */
|
|
2406
|
+
haloWidth?: Interpolated<number>;
|
|
2407
|
+
/** Размытие обводки текста в пикселях — `text-halo-blur` MapLibre. */
|
|
2408
|
+
haloBlur?: Interpolated<number>;
|
|
2409
|
+
/** Размытие обводки значка — `icon-halo-blur`. */
|
|
2410
|
+
iconHaloBlur?: Interpolated<number>;
|
|
2411
|
+
/**
|
|
2412
|
+
* Свой цвет значка — иначе он красится цветом подписи (одна программа на
|
|
2413
|
+
* текст и иконки). Нужен плашкам: щит номера трассы это светлая заливка с
|
|
2414
|
+
* рамкой, а номер на ней тёмный.
|
|
2415
|
+
*/
|
|
2416
|
+
/**
|
|
2417
|
+
* НАСЫЩЕННОСТЬ ПОДПИСИ: добавка к толщине штриха в пикселях (0 — как в шрифте).
|
|
2418
|
+
*
|
|
2419
|
+
* Своего полужирного начертания у нас нет: глифы приходят одним набором с сервера шрифтов, и
|
|
2420
|
+
* второй набор — это вторая загрузка и второй атлас на каждую карту. Зато буква хранится
|
|
2421
|
+
* полем расстояний, а в нём «жирнее» — это просто сдвиг границы наружу: тот же контур,
|
|
2422
|
+
* отпущенный на доли пикселя. Так набирают полужирный и в Mapbox, и в Яндексе.
|
|
2423
|
+
*
|
|
2424
|
+
* Мера — пиксели экрана, а не условная единица: на глаз подпись прибавляет ровно столько,
|
|
2425
|
+
* и на любом кегле прибавка одна и та же.
|
|
2426
|
+
*/
|
|
2427
|
+
textWeight?: Interpolated<number>;
|
|
2428
|
+
iconColor?: Interpolated<string>;
|
|
2429
|
+
iconHaloColor?: Interpolated<string>;
|
|
2430
|
+
iconHaloWidth?: Interpolated<number>;
|
|
2431
|
+
/**
|
|
2432
|
+
* Заливка круглой подложки. По умолчанию — цвет обводки подписи: он в каждой
|
|
2433
|
+
* теме и есть «цвет фона под текстом», светлый на дневных палитрах и тёмный
|
|
2434
|
+
* на ночных, так что кружок подхватывает тему без отдельной настройки.
|
|
2435
|
+
*/
|
|
2436
|
+
frameColor?: Interpolated<string>;
|
|
2437
|
+
/**
|
|
2438
|
+
* Непрозрачность ЗАЛИВКИ подложки, 0..1 (по умолчанию 1).
|
|
2439
|
+
*
|
|
2440
|
+
* Кружок под значком — фон, а не фигура: сплошной он закрывает карту и на
|
|
2441
|
+
* плотной застройке читается дырой. Полупрозрачный отделяет пиктограмму от
|
|
2442
|
+
* подложки, но оставляет видимым то, что под ним. Рамка сохраняет свою
|
|
2443
|
+
* непрозрачность — иначе кружок теряет край.
|
|
2444
|
+
*/
|
|
2445
|
+
frameOpacity?: Interpolated<number>;
|
|
2446
|
+
/** Рамка подложки. По умолчанию — цвет значка, приглушённый до трети. */
|
|
2447
|
+
frameHaloColor?: Interpolated<string>;
|
|
2448
|
+
frameHaloWidth?: Interpolated<number>;
|
|
2449
|
+
/**
|
|
2450
|
+
* ГРАДИЕНТ ПО ПОДЛОЖКЕ: насколько верх кружка светлее, а низ темнее своего цвета (0..1,
|
|
2451
|
+
* по умолчанию 0 — ровная заливка).
|
|
2452
|
+
*
|
|
2453
|
+
* Задан силой, а не парой цветов, нарочно. Цвет у подложки один на категорию — у еды свой,
|
|
2454
|
+
* у транспорта свой, — и вторым цветом пришлось бы задавать их все заново, по два на каждую.
|
|
2455
|
+
* Светлота же считается от того цвета, что уже есть, поэтому объём получают сразу все
|
|
2456
|
+
* категории, и перекрашивание темы ничего не ломает.
|
|
2457
|
+
*/
|
|
2458
|
+
frameGradient?: Interpolated<number>;
|
|
2459
|
+
/**
|
|
2460
|
+
* ТЕНЬ ПОД ПОДЛОЖКОЙ: непрозрачность, 0..1 (по умолчанию 0 — без тени).
|
|
2461
|
+
*
|
|
2462
|
+
* Кружок без тени лежит В карте, с тенью — НАД ней, и на пёстрой застройке это разница между
|
|
2463
|
+
* «пятно среди домов» и «метка поверх города».
|
|
2464
|
+
*/
|
|
2465
|
+
frameShadow?: Interpolated<number>;
|
|
2466
|
+
/** Сдвиг тени вниз в пикселях экрана (по умолчанию 3). */
|
|
2467
|
+
frameShadowOffset?: Interpolated<number>;
|
|
2468
|
+
/** Размытие тени в пикселях экрана (по умолчанию 6). */
|
|
2469
|
+
frameShadowBlur?: Interpolated<number>;
|
|
2470
|
+
/**
|
|
2471
|
+
* Свой цвет тени. По умолчанию — цвет подложки, притемнённый: серая тень под цветным значком
|
|
2472
|
+
* читается грязью, а потемневший собственный цвет — глубиной.
|
|
2473
|
+
*/
|
|
2474
|
+
frameShadowColor?: Interpolated<string>;
|
|
2475
|
+
/**
|
|
2476
|
+
* Цвета частей составного значка (`layout.iconParts`), по порядку частей.
|
|
2477
|
+
*
|
|
2478
|
+
* Лежат в paint, а не рядом с именами частей: это ЦВЕТ, и тема вправе его перекрасить, как
|
|
2479
|
+
* перекрашивает всё остальное. Части без цвета красятся как обычный значок.
|
|
2480
|
+
*/
|
|
2481
|
+
partColors?: (Interpolated<string> | ColorFrom)[];
|
|
2482
|
+
/** Обводка частей, по порядку частей. По умолчанию её нет — см. `partColors`. */
|
|
2483
|
+
partHaloWidths?: Interpolated<number>[];
|
|
2484
|
+
opacity?: Interpolated<number>;
|
|
2485
|
+
/** Непрозрачность значка отдельно от подписи, `icon-opacity` (без поля — как `opacity`). */
|
|
2486
|
+
iconOpacity?: Interpolated<number>;
|
|
2487
|
+
/** Сдвиг подписи в пикселях `[x, y]`, `text-translate`. */
|
|
2488
|
+
textTranslate?: [number, number] | unknown[];
|
|
2489
|
+
/** От чего отсчитывается сдвиг подписи: `map` — по карте, `viewport` — по экрану. */
|
|
2490
|
+
textTranslateAnchor?: 'map' | 'viewport';
|
|
2491
|
+
/** Сдвиг значка в пикселях, `icon-translate`. */
|
|
2492
|
+
iconTranslate?: [number, number] | unknown[];
|
|
2493
|
+
iconTranslateAnchor?: 'map' | 'viewport';
|
|
2494
|
+
};
|
|
2495
|
+
}
|
|
2496
|
+
/**
|
|
2497
|
+
* Поверхность со своим уровнем: приподнятый парк, утопленная вода, площадка.
|
|
2498
|
+
*
|
|
2499
|
+
* От `fill` отличается тем, что живёт в объёме: у неё есть уровень (в том числе
|
|
2500
|
+
* отрицательный), борт-фаска и юбка до земли, она пишет глубину и получает
|
|
2501
|
+
* свет. От `fill-extrusion` — тем, что уровень задаёт СТИЛЬ, а не данные, и
|
|
2502
|
+
* вместо стены с окнами у неё мягкий край.
|
|
2503
|
+
*
|
|
2504
|
+
* Уровень и фаска — ГЕОМЕТРИЯ: их правка пересобирает тайлы.
|
|
2505
|
+
*/
|
|
2506
|
+
interface SurfaceLayerSpec extends LayerBase {
|
|
2507
|
+
type: 'surface';
|
|
2508
|
+
/** Уровень верхней плоскости в метрах; отрицательный — ниже земли. */
|
|
2509
|
+
elevation: number;
|
|
2510
|
+
/** До какого уровня опускается юбка. По умолчанию земля (0). */
|
|
2511
|
+
base?: number;
|
|
2512
|
+
/** Ширина фаски по горизонтали, метры. 0 — резкий край. */
|
|
2513
|
+
bevel?: number;
|
|
2514
|
+
/**
|
|
2515
|
+
* СТРОИТЬ ПОВЕРХНОСТЬ ИЗ ЛИНИЙ, а не из полигонов: полотно дороги, тротуар, дорожка.
|
|
2516
|
+
*
|
|
2517
|
+
* Дорога в данных — ось, а не площадь, и рисуется она лентой в экранных пикселях: у такой ленты
|
|
2518
|
+
* нет края в мире, поэтому нет и бордюра, и борта, и тени от него. С этим флагом ось
|
|
2519
|
+
* превращается в контур (`generators/ribbon`), и полотно становится обычной поверхностью — со
|
|
2520
|
+
* своим уровнем, фаской и юбкой. Ширина берётся из данных (атрибут `width`, метры), а если её
|
|
2521
|
+
* там нет — из `width` ниже.
|
|
2522
|
+
*/
|
|
2523
|
+
fromLines?: boolean;
|
|
2524
|
+
/** Ширина полотна в метрах, когда в данных её нет (тропинка, тротуар). Только с `fromLines`. */
|
|
2525
|
+
width?: number;
|
|
2526
|
+
/** Прибавка к ширине из данных, метры: обочина, свес бордюра. Только с `fromLines`. */
|
|
2527
|
+
widthExtra?: number;
|
|
2528
|
+
/**
|
|
2529
|
+
* Толщина плиты у ПРИПОДНЯТОГО полотна (мост, эстакада), метры.
|
|
2530
|
+
*
|
|
2531
|
+
* Мост без низа читается плёнкой, висящей над улицей: сверху асфальт, а дальше сразу земля.
|
|
2532
|
+
* Толщина даёт ему боковую стенку — ту же, что у берега приподнятой поверхности.
|
|
2533
|
+
*/
|
|
2534
|
+
deck?: number;
|
|
2535
|
+
/** На сколько фаска опускается, метры. */
|
|
2536
|
+
/**
|
|
2537
|
+
* Насколько широкую щель между кусками СЛИТЬ, метры. По умолчанию — общее значение движка.
|
|
2538
|
+
*
|
|
2539
|
+
* Ноль нужен слоям, куски которых обязаны остаться порознь. Первый такой — зебра перехода: она
|
|
2540
|
+
* набрана отдельными полосами с промежутками около метра, и общая сварка слепила её в сплошную
|
|
2541
|
+
* белую плиту.
|
|
2542
|
+
*/
|
|
2543
|
+
weld?: number;
|
|
2544
|
+
/**
|
|
2545
|
+
* УЧАСТВУЕТ ЛИ ПОВЕРХНОСТЬ В ПОЛЕ ВЫСОТ, по которому поднимаются линии. По умолчанию — да.
|
|
2546
|
+
*
|
|
2547
|
+
* Поле отвечает на вопрос «на чём лежит линия»: дорожка, проходящая по приподнятому двору,
|
|
2548
|
+
* поднимается вместе с ним (см. `generators/ground`). Полотну дорог это во вред: линия, которая
|
|
2549
|
+
* просто ПЕРЕСЕКАЕТ асфальт, взбирается на него и рисуется поверх. Самое заметное — русло реки:
|
|
2550
|
+
* мост через неё выходит перечёркнутым синей полосой ровно по проезжей части.
|
|
2551
|
+
*
|
|
2552
|
+
* Поэтому полотно из поля исключается. Своей разметке оно ничего не должно: краска и так лежит
|
|
2553
|
+
* выше асфальта собственной отметкой.
|
|
2554
|
+
*/
|
|
2555
|
+
groundField?: boolean;
|
|
2556
|
+
/**
|
|
2557
|
+
* ПИШЕТ ЛИ ПОВЕРХНОСТЬ ГЛУБИНУ (по умолчанию — да, если непрозрачна и не утоплена; `surfaceWritesDepth`).
|
|
2558
|
+
*
|
|
2559
|
+
* `false` — как утопленная вода: поверхность ложится краской, а то, что стиль рисует следом, ложится
|
|
2560
|
+
* на неё по очереди. Нужна там, где следующий слой лежит выше на сантиметры и спорить за глубину
|
|
2561
|
+
* на Adreno проигрывает: наземное полотно (0.09 м) под асфальтом детальных дорог (0.25 м) давало
|
|
2562
|
+
* светлую линию вдоль асфальта (NaviGram натив, Худжанд, 31.10.2026). Поднятое полотно глубину
|
|
2563
|
+
* пишет по-прежнему — эстакада обязана закрывать то, что под ней.
|
|
2564
|
+
*/
|
|
2565
|
+
depthWrite?: boolean;
|
|
2566
|
+
bevelDrop?: number;
|
|
2567
|
+
paint: MaterialPaint & {
|
|
2568
|
+
/** Цвет поверхности; `{ from, darken }` — «как у такого-то слоя» (см. `ColorFrom`). */
|
|
2569
|
+
color: Interpolated<string> | ColorFrom;
|
|
2570
|
+
opacity?: Interpolated<number>;
|
|
2571
|
+
/** Насколько темнее борт и юбка, 0..1. */
|
|
2572
|
+
sideShade?: Interpolated<number>;
|
|
2573
|
+
/**
|
|
2574
|
+
* Цвет борта и юбки. По умолчанию у УТОПЛЕННОЙ поверхности это фон стиля —
|
|
2575
|
+
* то есть земля вокруг: стенка утопленной воды и есть берег, и красить её
|
|
2576
|
+
* водой значит обводить реку тёмной каймой.
|
|
2577
|
+
*
|
|
2578
|
+
* `{ from, darken }` — «как у такого-то слоя» (см. `ColorFrom`): так бордюр полотна берёт цвет
|
|
2579
|
+
* обводки дорог из темы и меняется вместе с ней, а не остаётся одним хексом на все палитры.
|
|
2580
|
+
*/
|
|
2581
|
+
sideColor?: Interpolated<string> | ColorFrom;
|
|
2582
|
+
/**
|
|
2583
|
+
* Насколько борт освещается КАК ЗЕМЛЯ (0 — по своей нормали, 1 — по
|
|
2584
|
+
* вертикальной). У берега нормаль горизонтальная, света он почти не
|
|
2585
|
+
* получает и читается тёмной стенкой; у утопленных поверхностей по
|
|
2586
|
+
* умолчанию 1, и край берёт свет окружающей земли.
|
|
2587
|
+
*/
|
|
2588
|
+
sideLight?: Interpolated<number>;
|
|
2589
|
+
/**
|
|
2590
|
+
* ТОН ПО ВЫСОТЕ: чем выше лежит верх поверхности, тем он светлее (> 0) или темнее (< 0).
|
|
2591
|
+
*
|
|
2592
|
+
* Уровни развязки читаются сверху, без наклона камеры: у Baidu нижняя дорога под эстакадой
|
|
2593
|
+
* заметно темнее верхней, а по длине съезда тон меняется плавно (замер их кадров,
|
|
2594
|
+
* `sdk/baydumap/RESEARCH.md` §6.4 в монорепозитории). Считается по высоте КАЖДОЙ вершины —
|
|
2595
|
+
* профиль подъёма (`liftPath`) даёт градиент по съезду сам, без нарезки на куски.
|
|
2596
|
+
*
|
|
2597
|
+
* Доля смешивания с белым (или чёрным) на полной высоте [`liftToneHeight`], 0..1. Земля
|
|
2598
|
+
* (верх ниже уровня слоя + четверти метра) не меняется — тема остаётся темой.
|
|
2599
|
+
*/
|
|
2600
|
+
liftTone?: Interpolated<number>;
|
|
2601
|
+
/** Высота, на которой тон набирает всю силу, метры. По умолчанию — `levelHeight` стиля или 8. */
|
|
2602
|
+
liftToneHeight?: number;
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
/**
|
|
2606
|
+
* Раскладка детальных 3D-объектов — общая у слоя стиля (`ModelLayerSpec.layout`) и у опции карты
|
|
2607
|
+
* `objects3d.layout`. У опции есть ещё порог показа `minZoom`; у слоя стиля его роль играет
|
|
2608
|
+
* `minzoom` самого слоя, как у любого слоя (см. `Objects3DLayout`).
|
|
2609
|
+
*/
|
|
2610
|
+
interface ModelLayout {
|
|
2611
|
+
/**
|
|
2612
|
+
* Радиусы в метрах: до какого расстояния грузим и до какого держим уже
|
|
2613
|
+
* загруженное. Второй заметно больше первого — иначе объект на границе
|
|
2614
|
+
* мигал бы при каждом дрожании камеры.
|
|
2615
|
+
*/
|
|
2616
|
+
loadRadius?: number;
|
|
2617
|
+
keepRadius?: number;
|
|
2618
|
+
/** Сколько моделей держать в памяти одновременно. */
|
|
2619
|
+
budget?: number;
|
|
2620
|
+
/** Прятать здание, которое модель заменяет (`replaces` + `anchor: replace`). */
|
|
2621
|
+
maskReplaced?: boolean;
|
|
2622
|
+
/**
|
|
2623
|
+
* Полная геометрия (lod0) с самого нижнего зума, без упрощённой ступени.
|
|
2624
|
+
*
|
|
2625
|
+
* По умолчанию у порога показа объект получает lod1 и «дорисовывается» до lod0 только через
|
|
2626
|
+
* два зума. На общем плане это незаметно, но если карта показывает объект как достопримечательность,
|
|
2627
|
+
* читается браком: сначала огрублённый силуэт, потом подмена.
|
|
2628
|
+
*
|
|
2629
|
+
* Число объектов флаг НЕ трогает — за него отвечает `fullBudget`. Разделены они не для порядка:
|
|
2630
|
+
* замер на боевой карте (Душанбе, z15.2, окно 1551×1346, наклон 55°) показал, что кадр сажает
|
|
2631
|
+
* именно количество, а не подробность — со снятыми обеими поблажками медиана кадра при панораме
|
|
2632
|
+
* была 30–38 мс против 17 мс на z17.8.
|
|
2633
|
+
*/
|
|
2634
|
+
fullDetail?: boolean;
|
|
2635
|
+
/**
|
|
2636
|
+
* Полный бюджет моделей с нижнего зума.
|
|
2637
|
+
*
|
|
2638
|
+
* По умолчанию на пороге показа берётся четверть бюджета, и дальше он плавно растёт до полного
|
|
2639
|
+
* за три зума: на общем плане объект занимает считанные пиксели, и сотня таких объектов стоит
|
|
2640
|
+
* кадра и трафика, ничего не добавляя глазу. Включать на широком экране с осторожностью —
|
|
2641
|
+
* модели дают около 84 % треугольников кадра.
|
|
2642
|
+
*/
|
|
2643
|
+
fullBudget?: boolean;
|
|
2644
|
+
}
|
|
2645
|
+
/** Раскладка опции карты `objects3d`: то же, что у слоя, плюс порог показа. */
|
|
2646
|
+
interface Objects3DLayout extends ModelLayout {
|
|
2647
|
+
/**
|
|
2648
|
+
* С какого зума показывать. Ниже него объекты не грузятся вовсе: детальная
|
|
2649
|
+
* модель на общем плане не читается, а трафик и память тратит.
|
|
2650
|
+
*/
|
|
2651
|
+
minZoom?: number;
|
|
2652
|
+
}
|
|
2653
|
+
/**
|
|
2654
|
+
* ДЕТАЛЬНЫЕ 3D-ОБЪЕКТЫ СЛОЕМ СТИЛЯ (тип `model`, в v2 — `osmgl-model`).
|
|
2655
|
+
*
|
|
2656
|
+
* Тайл источника говорит, ГДЕ стоит модель (набор `model3d`), сама модель — отдельный GLB из
|
|
2657
|
+
* сервиса Objects3D: его адрес — свойство ИСТОЧНИКА (`SourceSpec.modelEndpoint`), потому что номера
|
|
2658
|
+
* файлов в тайле имеют смысл только у того сервиса, из базы которого тайл собран.
|
|
2659
|
+
*
|
|
2660
|
+
* Слой ничего не рисует в общей очереди слоёв: он превращает точки тайла в список моделей, а рисует
|
|
2661
|
+
* их общий проход моделей — вместе со зданиями и с общей картой теней. Поэтому место слоя в списке
|
|
2662
|
+
* на облик не влияет, а рисующие проходы его пропускают (как проход заливок пропускает подписи).
|
|
2663
|
+
*
|
|
2664
|
+
* Раньше объекты задавались только опцией карты `objects3d`, и стиль не мог их ни объявить, ни
|
|
2665
|
+
* спрятать, ни настроить — в редакторе стилей их не было вовсе. Опция осталась путём совместимости:
|
|
2666
|
+
* стиль без такого слоя плюс опция ведут себя как прежде, а слой в стиле главнее опции.
|
|
2667
|
+
*
|
|
2668
|
+
* Имена — в духе слоя `model` Mapbox GL v3 (`model-opacity`, `model-cast-shadows`), но источник и
|
|
2669
|
+
* политика загрузки свои: у Mapbox модель берётся из корня стиля по `model-id`, у нас — из сервиса
|
|
2670
|
+
* по номеру файла в тайле, с радиусами и бюджетом памяти.
|
|
2671
|
+
*
|
|
2672
|
+
* `minzoom` слоя — порог показа (ниже него модели отпускаются); без поля — 14, как у опции.
|
|
2673
|
+
* `filter` отбирает размещения по свойствам тайла (`kind: rule` — замены по типу).
|
|
2674
|
+
*/
|
|
2675
|
+
interface ModelLayerSpec {
|
|
2676
|
+
/** id слоя; он же ключ бакета размещений в тайле. */
|
|
2677
|
+
id: string;
|
|
2678
|
+
type: 'model';
|
|
2679
|
+
/** Источник размещений; без поля — `base`, но у основной карты размещений нет. */
|
|
2680
|
+
source?: string;
|
|
2681
|
+
'source-layer': string;
|
|
2682
|
+
filter?: Filter;
|
|
2683
|
+
minzoom?: number;
|
|
2684
|
+
maxzoom?: number;
|
|
2685
|
+
visible?: boolean;
|
|
2686
|
+
/** Свободные данные приложения у слоя (`metadata` слоя MapLibre). Движок их не читает. */
|
|
2687
|
+
metadata?: Record<string, unknown>;
|
|
2688
|
+
layout?: ModelLayout;
|
|
2689
|
+
paint?: {
|
|
2690
|
+
/**
|
|
2691
|
+
* Непрозрачность моделей, 0..1. Меньше единицы — модель уходит в прозрачный подпроход (без
|
|
2692
|
+
* записи глубины), как при плавном исчезновении, и рисуется по одной, а не пачкой.
|
|
2693
|
+
*/
|
|
2694
|
+
opacity?: Interpolated<number>;
|
|
2695
|
+
/** Отбрасывают ли модели тень в общую карту теней. Получают её в любом случае. */
|
|
2696
|
+
castShadows?: boolean;
|
|
2697
|
+
};
|
|
2698
|
+
}
|
|
2699
|
+
type StyleLayerSpec = FillLayerSpec | LineLayerSpec | FillExtrusionLayerSpec | SurfaceLayerSpec | SymbolLayerSpec | RasterLayerSpec | ModelLayerSpec | CircleLayerSpec | BackgroundLayerSpec | HeatmapLayerSpec | HillshadeLayerSpec | ColorReliefLayerSpec;
|
|
2700
|
+
/**
|
|
2701
|
+
* Освещение сцены: ровный ambient + ДВА направленных источника.
|
|
2702
|
+
*
|
|
2703
|
+
* Ключевой (key) задаёт основную светотень, заполняющий (fill) светит примерно
|
|
2704
|
+
* с противоположной стороны и вытягивает грани, отвёрнутые от ключевого.
|
|
2705
|
+
*
|
|
2706
|
+
* Почему не полусфера (небо сверху / отсвет земли снизу), с которой начинали:
|
|
2707
|
+
* у любой вертикальной стены normal.z = 0, а значит полусферный ambient у всех
|
|
2708
|
+
* четырёх сторон дома ОДИНАКОВ. Отличал их только один солнечный член, и здания
|
|
2709
|
+
* читались плоскими. С двумя источниками каждая ориентация стены получает свою
|
|
2710
|
+
* яркость, и объём виден без всяких теней.
|
|
2711
|
+
*/
|
|
2712
|
+
interface LightSpec {
|
|
2713
|
+
/** Ровная подсветка со всех сторон. */
|
|
2714
|
+
ambientColor: string;
|
|
2715
|
+
ambientIntensity: number;
|
|
2716
|
+
/** Ключевой источник: азимут в градусах (0 — север, по часовой) и высота над горизонтом. */
|
|
2717
|
+
keyAzimuth: number;
|
|
2718
|
+
keyAltitude: number;
|
|
2719
|
+
keyColor: string;
|
|
2720
|
+
keyIntensity: number;
|
|
2721
|
+
/** Заполняющий источник — обычно с другой стороны и ниже. */
|
|
2722
|
+
fillAzimuth: number;
|
|
2723
|
+
fillAltitude: number;
|
|
2724
|
+
fillColor: string;
|
|
2725
|
+
fillIntensity: number;
|
|
2726
|
+
/**
|
|
2727
|
+
* Сила теней, 0..1 (по умолчанию 1). Ноль — теней нет ВОВСЕ: проход карты теней не запускается.
|
|
2728
|
+
*
|
|
2729
|
+
* Заведено ради стеклянных тем по образцу Baidu: там город светится, и серое пятно у основания
|
|
2730
|
+
* каждого дома читается грязью. Дробное значение ослабляет тень на земле.
|
|
2731
|
+
*/
|
|
2732
|
+
shadowStrength?: number;
|
|
2733
|
+
}
|
|
2734
|
+
/**
|
|
2735
|
+
* Небо и дымка.
|
|
2736
|
+
*
|
|
2737
|
+
* Дальность дымки меряется **в расстояниях от камеры до центра карты**, а не в
|
|
2738
|
+
* метрах и не в пикселях. Так же сделано в Mapbox (`range + 0.5/tan(fov/2)`),
|
|
2739
|
+
* и причина не в удобстве, а в том, что иначе дымка затягивает карту при
|
|
2740
|
+
* взгляде СВЕРХУ.
|
|
2741
|
+
*
|
|
2742
|
+
* При наклоне 0° вся видимая земля равноудалена от камеры — она лежит примерно
|
|
2743
|
+
* на одном расстоянии до центра (у края кадра всего в 1,15 раза дальше). Любой
|
|
2744
|
+
* порог в метрах либо срабатывает сразу на всём кадре, либо не срабатывает
|
|
2745
|
+
* никогда, и подобрать его на все зумы невозможно: на z10 «1200 метров» — это
|
|
2746
|
+
* пол-экрана, на z18 — сто экранов.
|
|
2747
|
+
*
|
|
2748
|
+
* В относительных единицах порог сам собой оказывается ЗА пределами вида при
|
|
2749
|
+
* взгляде сверху и попадает в кадр при наклоне, где земля действительно уходит
|
|
2750
|
+
* вдаль. Настройка получается одна на все зумы.
|
|
2751
|
+
*/
|
|
2752
|
+
interface SkySpec {
|
|
2753
|
+
/** Рисовать небо и дымку. */
|
|
2754
|
+
enabled: boolean;
|
|
2755
|
+
/** Цвет открытого неба над полосой мглы. */
|
|
2756
|
+
skyColor: string;
|
|
2757
|
+
/**
|
|
2758
|
+
* Цвет ВЕРХНЕЙ АТМОСФЕРЫ — выше по кадру, где воздуха меньше и синь глубже.
|
|
2759
|
+
*
|
|
2760
|
+
* Третья остановка градиента. Двух цветов на небо не хватает: получается ровная заливка, по
|
|
2761
|
+
* которой не читается ни толща воздуха, ни высота. Так же устроено небо у Mapbox (`high-color`).
|
|
2762
|
+
*/
|
|
2763
|
+
highColor?: string;
|
|
2764
|
+
/** Цвет у горизонта. В него же уходит дальняя земля — отсюда бесшовный стык. */
|
|
2765
|
+
horizonColor: string;
|
|
2766
|
+
/**
|
|
2767
|
+
* Где дымка начинается и где забивает цвет полностью — в расстояниях от
|
|
2768
|
+
* камеры до центра карты. Значение 1 это ровно центр кадра, поэтому начало
|
|
2769
|
+
* обязано быть больше единицы, иначе дымка ляжет на весь вид сверху.
|
|
2770
|
+
*/
|
|
2771
|
+
fogRange: [number, number];
|
|
2772
|
+
/** Предел силы дымки: 1 — дальний план сливается с горизонтом полностью. */
|
|
2773
|
+
fogIntensity: number;
|
|
2774
|
+
/**
|
|
2775
|
+
* Вертикальный диапазон дымки в МЕТРАХ: с какой высоты она начинает отпускать геометрию и на
|
|
2776
|
+
* какой отпускает совсем. Мгла лежит слоем у земли, и башня из неё выходит — низ теряется,
|
|
2777
|
+
* верх остаётся чистым. Ровно выцветшая по всей высоте башня выдаёт нарисованную дымку первой.
|
|
2778
|
+
*
|
|
2779
|
+
* Равные значения выключают учёт высоты. Аналог `fog.vertical-range` у Mapbox.
|
|
2780
|
+
*/
|
|
2781
|
+
fogVerticalRange: [number, number];
|
|
2782
|
+
/** Цвет космоса за пределами атмосферы. Виден только на глобусе. */
|
|
2783
|
+
spaceColor: string;
|
|
2784
|
+
/** Цвет атмосферной каймы вокруг планеты. */
|
|
2785
|
+
atmosphereColor: string;
|
|
2786
|
+
/** Яркость звёзд, 0 — выключить. Звёзды закреплены в мире, а не на экране. */
|
|
2787
|
+
starIntensity: number;
|
|
2788
|
+
/**
|
|
2789
|
+
* Толщина полосы МГЛЫ над горизонтом — в синусе угла подъёма луча, как `fog.horizon-blend`
|
|
2790
|
+
* у Mapbox. Значение 0.14 это примерно восемь градусов.
|
|
2791
|
+
*
|
|
2792
|
+
* Величина угловая, а не доля кадра: толщина мглы от кадрирования не зависит. Доля видимого
|
|
2793
|
+
* неба схлопывается в ноль, когда горизонт подходит к кромке кадра (большой зум с наклоном), и
|
|
2794
|
+
* синее небо упирается в мглу стыком.
|
|
2795
|
+
*
|
|
2796
|
+
* Этой же полосой дымка отпускает геометрию по мере подъёма луча — небо и дальний дом обязаны
|
|
2797
|
+
* приходить у горизонта в один цвет.
|
|
2798
|
+
*/
|
|
2799
|
+
horizonBlend: number;
|
|
2800
|
+
/**
|
|
2801
|
+
* Чья модель неба и дымки. Без поля — своя (облик osmgl). `maplibre` ставит импортёр стиля MapLibre:
|
|
2802
|
+
* небо — градиент `sky.fragment.glsl` (квадрат по полосе в пикселях над горизонтом), дымка — только
|
|
2803
|
+
* с рельефом, по глубине `terrain.fragment.glsl` (`fog-color` → `horizon-color`, наклон 60–70°).
|
|
2804
|
+
*/
|
|
2805
|
+
model?: 'maplibre';
|
|
2806
|
+
/** Цвет дымки у земли (`fog-color`), только `model: maplibre`. */
|
|
2807
|
+
fogColor?: string;
|
|
2808
|
+
/** Где дымка начинается: 0 — центр кадра, 1 — горизонт (`fog-ground-blend`). */
|
|
2809
|
+
fogGroundBlend?: number;
|
|
2810
|
+
/** Где цвет дымки переходит в цвет горизонта (`horizon-fog-blend`). */
|
|
2811
|
+
horizonFogBlend?: number;
|
|
2812
|
+
/** Полоса перехода неба в горизонт, доля полувысоты кадра (`sky-horizon-blend`). */
|
|
2813
|
+
skyHorizonBlend?: number;
|
|
2814
|
+
/**
|
|
2815
|
+
* Этап (x): сила атмосферы на шаре (`atmosphere-blend`), 0 — её нет, 1 — во всю силу; по зуму. Множит
|
|
2816
|
+
* кайму у края планеты и ореол за ним. Без поля — 1 (облик osmgl); у стиля MapLibre — 0.8.
|
|
2817
|
+
*/
|
|
2818
|
+
atmosphereBlend?: Interpolated<number>;
|
|
2819
|
+
}
|
|
2820
|
+
declare const DEFAULT_SKY: SkySpec;
|
|
2821
|
+
/**
|
|
2822
|
+
* ТУМАН С ДАЛЬНОСТЬЮ ОТСЕЧЕНИЯ — корневое `fog` стиля (как у Apple Maps: при большом наклоне дальний
|
|
2823
|
+
* план уходит в сплошную стену тумана, а за ней не рисуется и не грузится НИЧЕГО).
|
|
2824
|
+
*
|
|
2825
|
+
* Дальности меряются в РАССТОЯНИЯХ ОТ КАМЕРЫ ДО ЦЕНТРА КАДРА и ВДОЛЬ ОСИ ВЗГЛЯДА (как глубина в
|
|
2826
|
+
* шейдере): 1 — центр кадра. У карты сверху вся земля лежит ровно на единице, поэтому любой туман
|
|
2827
|
+
* дальше 1 её не трогает и появляется только с наклоном. Граница одинаковой глубины на земле — прямая,
|
|
2828
|
+
* параллельная краю экрана, отсюда ровная горизонтальная кромка тумана. Отсечение — той же плоскостью
|
|
2829
|
+
* (дальняя плоскость камеры), поэтому кромка геометрии не видна: на ней туман уже сплошной.
|
|
2830
|
+
*
|
|
2831
|
+
* Без поля `fog` — прежняя дымка неба (`SkySpec.fogRange`), ничего не отсекается сверх прежнего.
|
|
2832
|
+
*/
|
|
2833
|
+
interface FogSpec {
|
|
2834
|
+
/** Где туман начинается и где он уже сплошной (в расстояниях до центра кадра, начало > 1). */
|
|
2835
|
+
range: [number, number];
|
|
2836
|
+
/** Цвет тумана; он же цвет горизонта неба — так стык невидим. Без поля — `sky.horizonColor`. */
|
|
2837
|
+
color?: string;
|
|
2838
|
+
/** Дальше этого не грузится и не рисуется ничего. Без поля — конец тумана; ближе конца не бывает. */
|
|
2839
|
+
cutoff?: number;
|
|
2840
|
+
/** Высота плотной полосы тумана над горизонтом, градусы: сплошная дымка, уходящая вверх в небо. */
|
|
2841
|
+
height: number;
|
|
2842
|
+
/**
|
|
2843
|
+
* Плотность, 0..1: предел силы тумана. Ниже 1 дальний план просвечивает, и отсекать его без видимой
|
|
2844
|
+
* кромки нельзя — тогда отсечение включается только явным `cutoff`.
|
|
283
2845
|
*/
|
|
284
|
-
|
|
2846
|
+
density: number;
|
|
2847
|
+
/** Высоты в метрах, где туман начинает отпускать дома и где отпускает совсем (`vertical-range` Mapbox). */
|
|
2848
|
+
verticalRange?: [number, number];
|
|
285
2849
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
2850
|
+
/**
|
|
2851
|
+
* Туман по умолчанию — ПОЛОСА У ГОРИЗОНТА, а не стена посреди города.
|
|
2852
|
+
*
|
|
2853
|
+
* Линия глубины k лежит на (1 − 1/k)/tg(наклона) фокусов над центром кадра. Сплошной туман — с k = 4.5:
|
|
2854
|
+
* при наклоне 75° это ~19 % высоты кадра от верха, при 70° — ~7.5 %; начинается он с 1.3, до наклона
|
|
2855
|
+
* ≈52° не виден вовсе.
|
|
2856
|
+
*
|
|
2857
|
+
* ★ Было [1.3, 1.7] («как у Apple Maps»: стена на трети кадра при 75°). На наклоне 70° молоко начиналось
|
|
2858
|
+
* чуть выше центра кадра и прятало кварталы в 400–500 м за ним (жалоба: «туман перекрывает половину
|
|
2859
|
+
* контента», Худжанд, z16.5). Mapbox по умолчанию — [0.5, 10] высот экрана за центром, у нас это
|
|
2860
|
+
* ≈ [1.33, 7.7]. Взят промежуточный конец: замер на z16.5, 70° — тайлов в кадре 85 → 135 (у Mapbox-диапазона
|
|
2861
|
+
* 167), кварталы читаются до верхних ~15 % кадра. Дальше конец не отодвигаем: за кромкой не грузится
|
|
2862
|
+
* ничего, и это главная экономия на слабых телефонах при большом наклоне.
|
|
2863
|
+
*/
|
|
2864
|
+
declare const DEFAULT_FOG: FogSpec;
|
|
2865
|
+
/** Этап (x): кодировка векторного источника — `mvt` (по умолчанию) или `mlt` (MapLibre Tile, `source/mlt.ts`). */
|
|
2866
|
+
type TileEncodingSpec = 'mvt' | 'mlt';
|
|
2867
|
+
interface SourceSpec {
|
|
2868
|
+
/** Шаблон вида `/tileserver/data/indoor/{z}/{x}/{y}.pbf`. У `geojson` адреса нет. */
|
|
2869
|
+
url?: string;
|
|
306
2870
|
/**
|
|
307
|
-
*
|
|
2871
|
+
* Что лежит по адресу. Без поля — векторные тайлы, как было раньше.
|
|
308
2872
|
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
* «пропускает» установку, которой на самом деле нет. Дешевле объявить кеш недействительным, чем
|
|
312
|
-
* потом искать, почему исчезли подписи.
|
|
2873
|
+
* `raster` — подложка картинками: её не надо разбирать, поэтому она не идёт
|
|
2874
|
+
* через пул воркеров и рисуется одним квадом на тайл (см. `RasterSource`).
|
|
313
2875
|
*/
|
|
314
|
-
|
|
315
|
-
useProgram(program: WebGLProgram | null): boolean;
|
|
316
|
-
bindVAO(vao: WebGLVertexArrayObject | null): void;
|
|
2876
|
+
type?: 'vector' | 'raster' | 'raster-dem' | 'geojson' | 'image' | 'video' | 'canvas';
|
|
317
2877
|
/**
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
* возвращаются с bindFramebuffer(null), и без этой подмены весь кадр после
|
|
321
|
-
* первого же такого прохода уходил бы мимо буфера.
|
|
2878
|
+
* Четыре угла картинки, видео или canvas: левый верхний, правый верхний, правый нижний, левый
|
|
2879
|
+
* нижний. Порядок и смысл как у MapLibre — углы независимы, прямоугольник необязателен.
|
|
322
2880
|
*/
|
|
323
|
-
|
|
2881
|
+
coordinates?: unknown;
|
|
2882
|
+
/** Элемент canvas или его id (`type: 'canvas'`). */
|
|
2883
|
+
canvas?: unknown;
|
|
2884
|
+
/** Перезаливать ли текстуру каждый кадр (живой canvas). */
|
|
2885
|
+
animate?: boolean;
|
|
324
2886
|
/**
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
2887
|
+
* ДАННЫЕ ПРИЛОЖЕНИЯ вместо тайлов с сервера (`type: 'geojson'`).
|
|
2888
|
+
*
|
|
2889
|
+
* Сам набор или адрес, откуда его забрать. Нарезкой на тайлы занимается движок
|
|
2890
|
+
* (`source/geojson-source.ts`), поэтому слои ссылаются на такой источник как на обычный.
|
|
328
2891
|
*/
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
setDepthTest(on: boolean): void;
|
|
339
|
-
setDepthMask(on: boolean): void;
|
|
2892
|
+
data?: unknown;
|
|
2893
|
+
/** Имя слоя внутри источника: на него смотрит `source-layer` слоя стиля. По умолчанию `geojson`. */
|
|
2894
|
+
sourceLayer?: string;
|
|
2895
|
+
/** Собирать ли точки в кластеры (`geojson`). */
|
|
2896
|
+
cluster?: boolean;
|
|
2897
|
+
/** Радиус кластера в пикселях экрана. */
|
|
2898
|
+
clusterRadius?: number;
|
|
2899
|
+
/** Зум, выше которого кластеров нет. */
|
|
2900
|
+
clusterMaxZoom?: number;
|
|
340
2901
|
/**
|
|
341
|
-
*
|
|
342
|
-
* геометрия перекрывает то, что нарисуют дальше, но сама не видна (так
|
|
343
|
-
* закрываются дырки в утопленных поверхностях — острова).
|
|
2902
|
+
* Кодировка высоты у `raster-dem`: `mapbox` (наш набор) или `terrarium`. См. `source/dem.ts`.
|
|
344
2903
|
*/
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
2904
|
+
encoding?: 'mapbox' | 'terrarium' | 'custom' | TileEncodingSpec;
|
|
2905
|
+
/**
|
|
2906
|
+
* База сервиса 3D-моделей (Objects3D) у источника размещений, например `/objects3d`.
|
|
2907
|
+
*
|
|
2908
|
+
* Номер файла в тайле размещений имеет смысл только у того сервиса, из базы которого собран тайл,
|
|
2909
|
+
* поэтому адрес — свойство ИСТОЧНИКА, а не слоя. Ключ портала (`?key=`) отдельно писать не нужно:
|
|
2910
|
+
* он берётся из адреса тайлов того же источника — шлюз пускает к тайлам и к моделям одним ключом.
|
|
2911
|
+
* Без поля — `/objects3d` (или `objects3d.endpoint` опции карты). Относительный адрес в стиле,
|
|
2912
|
+
* загруженном по ссылке, разрешается по адресу стиля.
|
|
2913
|
+
*/
|
|
2914
|
+
modelEndpoint?: string;
|
|
2915
|
+
minzoom?: number;
|
|
2916
|
+
maxzoom?: number;
|
|
2917
|
+
/** Все шаблоны адреса (`tiles` MapLibre), если их больше одного: тайл берёт `(x + y) % n`-й. `url` — первый. */
|
|
2918
|
+
tiles?: string[];
|
|
2919
|
+
/** `tms` — ось Y снизу вверх (`y = 2^z − 1 − y`), как у MapLibre. */
|
|
2920
|
+
scheme?: 'xyz' | 'tms';
|
|
2921
|
+
/** Рамка данных `[запад, юг, восток, север]`: тайлы вне неё не запрашиваются. */
|
|
2922
|
+
bounds?: [number, number, number, number];
|
|
2923
|
+
/** Сторона растрового тайла в пикселях (`raster`/`raster-dem`): 256 — тайлы на зум мельче. */
|
|
2924
|
+
tileSize?: number;
|
|
2925
|
+
/** Подпись источника для элемента атрибуции. */
|
|
2926
|
+
attribution?: string;
|
|
2927
|
+
/** Свойство, которое служит номером фичи (`["id"]`, `setFeatureState`); у слоёв — своё на каждый. */
|
|
2928
|
+
promoteId?: string | Record<string, string>;
|
|
2929
|
+
/** Не кешировать тайлы источника (`volatile`): у нас кеш в памяти, на диск ничего не пишется. */
|
|
2930
|
+
volatile?: boolean;
|
|
2931
|
+
/** Кодировка `custom` у `raster-dem`: высота = r·red + g·green + b·blue − baseShift. */
|
|
2932
|
+
redFactor?: number;
|
|
2933
|
+
greenFactor?: number;
|
|
2934
|
+
blueFactor?: number;
|
|
2935
|
+
baseShift?: number;
|
|
2936
|
+
/** `geojson`: поле тайла в пикселях (512-пиксельного тайла), упрощение, отбор фич выражением. */
|
|
2937
|
+
buffer?: number;
|
|
2938
|
+
tolerance?: number;
|
|
2939
|
+
filter?: unknown;
|
|
2940
|
+
/** `geojson`: номер фичи — её порядковый номер в наборе. */
|
|
2941
|
+
generateId?: boolean;
|
|
2942
|
+
/** `geojson`: сколько точек нужно на кластер (MapLibre — 2). */
|
|
2943
|
+
clusterMinPoints?: number;
|
|
2944
|
+
/** `geojson`: свойства кластера — `{ имя: [свёртка, выражение] }`, как у MapLibre. */
|
|
2945
|
+
clusterProperties?: Record<string, unknown>;
|
|
2946
|
+
/** `geojson`: длина вдоль линии для `line-gradient` (ждёт `line-progress` в рендере). */
|
|
2947
|
+
lineMetrics?: boolean;
|
|
355
2948
|
}
|
|
356
|
-
|
|
357
2949
|
/**
|
|
358
|
-
*
|
|
2950
|
+
* РЕЛЬЕФ: земля перестаёт быть плоскостью.
|
|
359
2951
|
*
|
|
360
|
-
* `
|
|
361
|
-
*
|
|
2952
|
+
* `source` — имя источника типа `raster-dem`, `exaggeration` — множитель высоты (1 — как в
|
|
2953
|
+
* данных, 0 — рельеф выключен). Высоту читает вершинный шейдер каждого слоя, который лежит по
|
|
2954
|
+
* земле: заливки, поверхности, дороги. Разбор подхода MapLibre и наш план — в `porting/terrain.md`.
|
|
2955
|
+
*
|
|
2956
|
+
* Тип ИМЕНОВАННЫЙ, а не инлайновый: его принимает `map.setTerrain` — тот самый метод, которым
|
|
2957
|
+
* рельеф включают на лету (имя и смысл как у MapLibre).
|
|
362
2958
|
*/
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
private readonly _program;
|
|
367
|
-
private uniforms;
|
|
368
|
-
private attribs;
|
|
2959
|
+
interface TerrainSpec {
|
|
2960
|
+
source: string;
|
|
2961
|
+
exaggeration?: number;
|
|
369
2962
|
/**
|
|
370
|
-
*
|
|
2963
|
+
* ЧЕМ РЕЛЬЕФ ПОКАЗАН, кроме собственной формы.
|
|
371
2964
|
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* решает то же блоками по частоте (`OsmglFrame`/`OsmglMaterial`), у GL — вот этот кеш.
|
|
2965
|
+
* Сверху склон почти не читается — на бумажных картах его для того и красят по высоте
|
|
2966
|
+
* (гипсометрия) и отмывают светом. Оба тона здесь, а не в движке, потому что это ЦВЕТ: у
|
|
2967
|
+
* ледяной темы он холодный, у ночной тёмный, и одним набором на все темы не обойтись.
|
|
376
2968
|
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
* юниформа (`WebGLUniformLocation`), значения — копией (рендерер правит матрицы на месте). Сравнение — по
|
|
380
|
-
* числам JS, без `fround`: два разных числа с одним `float32` уйдут дважды, но лишнего не сэкономим никогда.
|
|
381
|
-
* Целые — отдельно: `Float64Array` с ними не путается, но `uniform1i` и `uniform1f` — разные вызовы.
|
|
2969
|
+
* `low`/`high` — тон низин и вершин, `range` — между какими высотами растянут переход,
|
|
2970
|
+
* `tint`/`shade` — насколько сильно подмешивать окраску и отмывку (0..1).
|
|
382
2971
|
*/
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
2972
|
+
tint?: {
|
|
2973
|
+
/**
|
|
2974
|
+
* Тона шкалы высот. НЕОБЯЗАТЕЛЬНЫ: без них рельеф остаётся в цветах самой карты, а объём ему
|
|
2975
|
+
* даёт одна отмывка. Так и нужно, когда карта уже раскрашена по смыслу — окраска по высоте
|
|
2976
|
+
* тогда спорит с ней за внимание.
|
|
2977
|
+
*
|
|
2978
|
+
* Три режима:
|
|
2979
|
+
* ни одного тона — только отмывка;
|
|
2980
|
+
* один `high` — тон нарастает к вершинам, низины остаются цветом карты;
|
|
2981
|
+
* `low` и `high` — полная гипсометрическая шкала по всему диапазону.
|
|
2982
|
+
*/
|
|
2983
|
+
low?: string;
|
|
2984
|
+
/** Тон середины: между долиной и вершиной лежат склоны, и без своего тона они пропадают. */
|
|
2985
|
+
mid?: string;
|
|
2986
|
+
high?: string;
|
|
2987
|
+
range?: [number, number];
|
|
2988
|
+
tint?: number;
|
|
2989
|
+
shade?: number;
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
interface StyleSpec {
|
|
2993
|
+
version: 1;
|
|
2994
|
+
name?: string;
|
|
2995
|
+
/** Цвет подложки. */
|
|
2996
|
+
background: string;
|
|
2997
|
+
/** Этап (d): плавная смена покраски по умолчанию (`transition` корня MapLibre). Без поля — сразу. */
|
|
2998
|
+
transition?: TransitionSpec;
|
|
387
2999
|
/**
|
|
388
|
-
*
|
|
3000
|
+
* НА СКОЛЬКО МЕТРОВ ПОДНИМАЕТ КАЖДЫЙ УРОВЕНЬ ПЕРЕСЕЧЕНИЯ (`generators/level`): мост — 1, земля —
|
|
3001
|
+
* 0, тоннель — −1.
|
|
389
3002
|
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
3003
|
+
* Пока дороги были краской, уровень решал только ПОРЯДОК отрисовки (см. `network`). Полотно —
|
|
3004
|
+
* геометрия, и на пересечении без подъёма эстакада и улица под ней оказались бы на одной высоте:
|
|
3005
|
+
* два непрозрачных верха в одной плоскости.
|
|
3006
|
+
*
|
|
3007
|
+
* Число нарочно маленькое. Настоящая эстакада поднята на пять метров и более, но опор и съездов
|
|
3008
|
+
* у нас нет: на такой высоте мост обрывался бы в воздухе там, где кончается его пролёт. Полметра
|
|
3009
|
+
* хватает, чтобы пересечение читалось «над», и не хватает, чтобы стык с обычной дорогой стал
|
|
3010
|
+
* ступенькой.
|
|
3011
|
+
*
|
|
3012
|
+
* ВНИЗ НЕ ОПУСКАЕМ: землю мы не разрезаем, и тоннель под ней просто исчез бы вместе со своей
|
|
3013
|
+
* подписью. Он остаётся на уровне земли — ровно так же, как рисовался лентой до сих пор.
|
|
396
3014
|
*/
|
|
397
|
-
|
|
398
|
-
|
|
3015
|
+
levelHeight?: number;
|
|
3016
|
+
light?: Partial<LightSpec>;
|
|
3017
|
+
/** Свет объёма MapLibre — корневой `light` стиля MapLibre (см. `MapLibreLightSpec`). */
|
|
3018
|
+
mapLibreLight?: Partial<MapLibreLightSpec>;
|
|
3019
|
+
/** Небо и дымка. */
|
|
3020
|
+
sky?: Partial<SkySpec>;
|
|
3021
|
+
/** Туман с дальностью отсечения (см. `FogSpec`). Нет — прежняя дымка неба без отсечения сверх неё. */
|
|
3022
|
+
fog?: Partial<FogSpec>;
|
|
3023
|
+
/** Дополнительные источники тайлов помимо `base` (его задаёт карта опцией `tiles`). */
|
|
3024
|
+
sources?: Record<string, SourceSpec>;
|
|
3025
|
+
/** Рельеф под картой (см. `TerrainSpec`). */
|
|
3026
|
+
terrain?: TerrainSpec;
|
|
399
3027
|
/**
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
3028
|
+
* Ключ варианта 3D-моделей (см. `ThemeSpec.model3dKey`).
|
|
3029
|
+
*
|
|
3030
|
+
* Лежит в стиле, а не в опциях карты, потому что его задаёт ТЕМА, а тема — это накладка на стиль.
|
|
3031
|
+
* Менеджер моделей читает его отсюда после каждого `setStyle` и сам решает, что перезагрузить.
|
|
403
3032
|
*/
|
|
404
|
-
|
|
405
|
-
/** Программа GL. Первое обращение дожидается сборки (см. `pending`). */
|
|
406
|
-
get program(): WebGLProgram;
|
|
407
|
-
/** Сборка не удалась: каждое следующее обращение бросает ту же ошибку, а не рисует удалённой программой. */
|
|
408
|
-
private failure;
|
|
3033
|
+
model3dKey?: string;
|
|
409
3034
|
/**
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
3035
|
+
* Свободные данные приложения — как `metadata` у MapLibre. Движок их не читает; хранит редактор
|
|
3036
|
+
* стилей (своё состояние) и продукт (`maps3d:*` — облик SDK). Объявлено, чтобы проверка стиля не
|
|
3037
|
+
* считала поле опечаткой.
|
|
413
3038
|
*/
|
|
414
|
-
|
|
415
|
-
/** Дождаться сборки, проверить её и разобрать места юниформов и атрибутов. */
|
|
416
|
-
private finish;
|
|
417
|
-
private cacheLocations;
|
|
418
|
-
use(): void;
|
|
419
|
-
attribLocation(name: string): number;
|
|
420
|
-
private loc;
|
|
421
|
-
/** Надо ли слать значение в GL: `false` — там уже лежит такое же. */
|
|
422
|
-
private changed;
|
|
423
|
-
private readonly scratch;
|
|
424
|
-
private changed4;
|
|
425
|
-
/** Юниформ, вырезанный оптимизатором, молча игнорируется — это нормально. */
|
|
426
|
-
setMat4(name: string, v: Float32Array): void;
|
|
427
|
-
/** mat3 по КОЛОНКАМ — как того ждёт GLSL. */
|
|
428
|
-
setMat3(name: string, v: ArrayLike<number>): void;
|
|
429
|
-
setFloat(name: string, v: number): void;
|
|
430
|
-
setInt(name: string, v: number): void;
|
|
431
|
-
setVec2(name: string, x: number, y: number): void;
|
|
432
|
-
setVec3(name: string, x: number, y: number, z: number): void;
|
|
433
|
-
setVec4(name: string, x: number, y: number, z: number, w: number): void;
|
|
434
|
-
setVec4v(name: string, v: ArrayLike<number>): void;
|
|
3039
|
+
metadata?: Record<string, unknown>;
|
|
435
3040
|
/**
|
|
436
|
-
*
|
|
437
|
-
* но ищем мы и по голому имени, потому что часть драйверов регистрирует его именно так.
|
|
3041
|
+
* ШРИФТЫ СТИЛЯ — шаблон адреса SDF-глифов `…/{fontstack}/{range}.pbf`, ровно как `glyphs` у MapLibre.
|
|
438
3042
|
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
3043
|
+
* Нет поля — шрифты карты (опция `fonts`, `setGlyphs`). Есть — стиль ставит свои на время, пока он
|
|
3044
|
+
* стоит, а стиль без них возвращает карте её собственные. Так стиль, сохранённый редактором или
|
|
3045
|
+
* переведённый из MapLibre, не теряет шрифтов, с которыми его рисовали.
|
|
441
3046
|
*/
|
|
442
|
-
|
|
443
|
-
/**
|
|
444
|
-
|
|
445
|
-
|
|
3047
|
+
glyphs?: string;
|
|
3048
|
+
/**
|
|
3049
|
+
* Этап (x): ШРИФТЫ-ФАЙЛЫ (`font-faces` MapLibre) — имя из `text-font` → файл шрифта целиком или на
|
|
3050
|
+
* диапазоны `unicode-range`. Буква из такого диапазона рисуется браузером из файла (только веб,
|
|
3051
|
+
* `text/font-faces.ts`), остальные — с сервера `glyphs`.
|
|
3052
|
+
*/
|
|
3053
|
+
fontFaces?: Record<string, string | {
|
|
3054
|
+
url: string;
|
|
3055
|
+
'unicode-range'?: string[];
|
|
3056
|
+
} | (string | {
|
|
3057
|
+
url: string;
|
|
3058
|
+
'unicode-range'?: string[];
|
|
3059
|
+
})[]>;
|
|
3060
|
+
/**
|
|
3061
|
+
* СПРАЙТ СТИЛЯ — адрес без расширения (`…/sprite`, к нему дописываются `.json`/`.png`, а на
|
|
3062
|
+
* плотном экране `@2x`) или список `{ id, url }` — форма та же, что у `sprite` MapLibre, чтобы
|
|
3063
|
+
* редактор и импортёр переносили её как есть. Значки дополнительного спрайта зовутся `id:имя`;
|
|
3064
|
+
* `id: 'default'` — основной, без приставки.
|
|
3065
|
+
*
|
|
3066
|
+
* Нет поля — значки карты (встроенные, `setSprite`/`addSprite`) не трогаются. Есть — правило то же,
|
|
3067
|
+
* что у `glyphs`: на время стиля его спрайт, после — снова карты.
|
|
3068
|
+
*/
|
|
3069
|
+
sprite?: string | {
|
|
3070
|
+
id: string;
|
|
3071
|
+
url: string;
|
|
3072
|
+
}[];
|
|
3073
|
+
layers: StyleLayerSpec[];
|
|
446
3074
|
}
|
|
447
|
-
|
|
448
3075
|
/**
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
* Два разных вопроса, но оба про «откуда берутся байты тайла»:
|
|
452
|
-
*
|
|
453
|
-
* `addProtocol('pmtiles', …)` — адрес вида `pmtiles://…` обслуживает приложение само: читает из
|
|
454
|
-
* одного файла, из IndexedDB, из WebAssembly-читалки;
|
|
3076
|
+
* СВЕТ ОБЪЁМА MapLibre — корневой `light` стиля MapLibre, как его читает `fill_extrusion_program`.
|
|
455
3077
|
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
* ★ И ТО И ДРУГОЕ ЖИВЁТ НА ГЛАВНОМ ПОТОКЕ.
|
|
460
|
-
*
|
|
461
|
-
* Так же у MapLibre, и по той же причине: обработчик приложенческий — ему нужны ключи, кеш и
|
|
462
|
-
* хранилища страницы. Требовать, чтобы он работал внутри воркера, значит требовать от приложения
|
|
463
|
-
* писать под воркер. Поэтому байты добываются здесь, а воркеру достаётся только разбор.
|
|
3078
|
+
* Свой свет (`LightSpec`) им не заменить: у MapLibre другая модель — ОДИН источник, яркость по
|
|
3079
|
+
* формуле от светлоты самого цвета и нижняя граница в оттенок света. Светит он только слоям с
|
|
3080
|
+
* `lighting: 'maplibre'`; наши темы его не видят.
|
|
464
3081
|
*/
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
3082
|
+
interface MapLibreLightSpec {
|
|
3083
|
+
/** `viewport` — источник привязан к экрану и поворачивается вместе с курсом камеры; `map` — к карте. */
|
|
3084
|
+
anchor: 'map' | 'viewport';
|
|
3085
|
+
/** `[r, азимут, полярный угол]` в градусах, как в спецификации: азимут 0 — верх (север у `map`). */
|
|
3086
|
+
position: [number, number, number];
|
|
3087
|
+
color: Interpolated<string>;
|
|
3088
|
+
intensity: Interpolated<number>;
|
|
3089
|
+
}
|
|
3090
|
+
/** Умолчания спецификации MapLibre (`light` в `v8.json`). */
|
|
3091
|
+
declare const DEFAULT_MAPLIBRE_LIGHT: MapLibreLightSpec;
|
|
3092
|
+
/**
|
|
3093
|
+
* Свет по умолчанию. Азимуты источников намеренно НЕ диагональные (120/300,
|
|
3094
|
+
* а не 135/315): на диагонали пары стен «восток/юг» и «запад/север» получают
|
|
3095
|
+
* одинаковую яркость и дом снова выглядит плоским. При этих значениях четыре
|
|
3096
|
+
* стороны дают заметно разные яркости (примерно 122, 135, 137, 160 из 255),
|
|
3097
|
+
* а крыша — 234 при фоне карты 236.
|
|
3098
|
+
*/
|
|
3099
|
+
declare const DEFAULT_LIGHT: LightSpec;
|
|
469
3100
|
|
|
470
3101
|
/** План для воркера: что именно строить из тайла. Должен пережить structured clone. */
|
|
471
3102
|
/** Слои, которые вообще строятся из тайла: у подложки строить нечего. */
|
|
@@ -2012,20 +4643,149 @@ interface ExpressionOperatorRef {
|
|
|
2012
4643
|
/** Раздел: данные, решения, шкалы, математика… */
|
|
2013
4644
|
group: string;
|
|
2014
4645
|
}
|
|
2015
|
-
declare const STYLE_REFERENCE: StyleReference;
|
|
4646
|
+
declare const STYLE_REFERENCE: StyleReference;
|
|
4647
|
+
/**
|
|
4648
|
+
* СВОИ ФЛАГИ v2 БЕЗ ПОЛЯ v1 — переключатели поведения (§1.2): без поля значение — как у MapLibre,
|
|
4649
|
+
* своё поведение движка включается явно. Конвертер v1 → v2 дописывает их во встроенные стили, чтобы
|
|
4650
|
+
* те рисовались как прежде.
|
|
4651
|
+
*/
|
|
4652
|
+
declare const STYLE_REFERENCE_V2_FLAGS: Record<string, Record<string, PropRef>>;
|
|
4653
|
+
/**
|
|
4654
|
+
* Операции выражений, которые понимает движок (`style/expression.ts`). Сверяется тестом со
|
|
4655
|
+
* списком `case` в `compile` — ни одной лишней и ни одной пропущенной.
|
|
4656
|
+
*/
|
|
4657
|
+
declare const STYLE_REFERENCE_EXPRESSIONS: Record<string, ExpressionOperatorRef>;
|
|
4658
|
+
/** Разделы выражений → названия. */
|
|
4659
|
+
declare const STYLE_REFERENCE_EXPRESSION_GROUPS: Record<string, string>;
|
|
4660
|
+
|
|
4661
|
+
/**
|
|
4662
|
+
* ФОРМАТ СТИЛЯ v2 = MapLibre v8 + `osmgl-*` (`porting/unified-style-format.md`).
|
|
4663
|
+
*
|
|
4664
|
+
* Внешний формат стиля osmgl — синтаксис MapLibre как есть: те же типы слоёв, имена свойств, поля
|
|
4665
|
+
* корня и источников, выражения и старые функции. Свои свойства лежат в тех же `paint`/`layout` с
|
|
4666
|
+
* приставкой `osmgl-` (геометрия — в `layout`, покраска — в `paint`), свой тип слоя —
|
|
4667
|
+
* `osmgl-surface`. Признак расширений — `metadata["osmgl:version"]: 2`; без него файл — «чистый
|
|
4668
|
+
* MapLibre», он же валидный v2.
|
|
4669
|
+
*
|
|
4670
|
+
* ★ ВНУТРЕННЯЯ МОДЕЛЬ ДВИЖКА ОСТАЛАСЬ v1 (`StyleSpec`). Переименовывать поля на трёх платформах
|
|
4671
|
+
* ради имён смысла нет: облик от этого не меняется, а порты читают поля строками по всему рендеру.
|
|
4672
|
+
* Поэтому v2 — формат обмена: загрузчик (`importMapLibreStyle`, расширенный чтением `osmgl-*`)
|
|
4673
|
+
* переводит его во внутреннюю модель, а конвертер здесь — обратно. Таблица имён ОДНА — поле `v2` у
|
|
4674
|
+
* записей `STYLE_REFERENCE`; этот модуль только собирает из неё словари и знает про особые случаи,
|
|
4675
|
+
* где перевод — не переименование (пунктир, капсула, якоря подписи, ссылка на цвет).
|
|
4676
|
+
*
|
|
4677
|
+
* ★ БЕЗ ПОЛЯ — УМОЛЧАНИЕ MapLibre. Иначе стиль MapLibre «без правок» рисовался бы не как в MapLibre.
|
|
4678
|
+
* Своё поведение движка включается явными флагами (§1.2): `osmgl-line-shape: capsule`,
|
|
4679
|
+
* `osmgl-lighting: osmgl`, `osmgl-roofs: auto`, `osmgl-height-from-data`, `osmgl-symbol-layout:
|
|
4680
|
+
* block` (своя система подписей целиком — с её умолчаниями), `osmgl-line-anchors`,
|
|
4681
|
+
* `osmgl-text-halo-tracking`. Конвертер v1 → v2 дописывает их во встроенные стили, и те рисуются
|
|
4682
|
+
* пиксель в пиксель как прежде — это проверяет `tests/style-v2.test.mjs`.
|
|
4683
|
+
*/
|
|
4684
|
+
/** Ключ признака v2 в `metadata` корня. */
|
|
4685
|
+
declare const OSMGL_VERSION_KEY = "osmgl:version";
|
|
4686
|
+
/** Значение признака: версия расширений osmgl поверх MapLibre v8. */
|
|
4687
|
+
declare const OSMGL_FORMAT_VERSION = 2;
|
|
4688
|
+
/** Стиль v2 (он же MapLibre v8) — в той форме, в какой его пишет конвертер. */
|
|
4689
|
+
interface StyleSpecV2 {
|
|
4690
|
+
version: 8;
|
|
4691
|
+
name?: string;
|
|
4692
|
+
metadata?: Record<string, unknown>;
|
|
4693
|
+
sources: Record<string, Record<string, unknown>>;
|
|
4694
|
+
layers: LayerSpecV2[];
|
|
4695
|
+
[key: string]: unknown;
|
|
4696
|
+
}
|
|
4697
|
+
interface LayerSpecV2 {
|
|
4698
|
+
id: string;
|
|
4699
|
+
type: string;
|
|
4700
|
+
source?: string;
|
|
4701
|
+
'source-layer'?: string;
|
|
4702
|
+
minzoom?: number;
|
|
4703
|
+
maxzoom?: number;
|
|
4704
|
+
filter?: unknown;
|
|
4705
|
+
metadata?: unknown;
|
|
4706
|
+
layout?: Record<string, unknown>;
|
|
4707
|
+
paint?: Record<string, unknown>;
|
|
4708
|
+
}
|
|
4709
|
+
/** Тема v2: та же накладка, ключи — имена v2 (`paint[id]["line-color"]`, `osmgl-light`). */
|
|
4710
|
+
interface ThemeSpecV2 {
|
|
4711
|
+
name: string;
|
|
4712
|
+
'osmgl-light'?: Record<string, unknown>;
|
|
4713
|
+
sky?: Record<string, unknown>;
|
|
4714
|
+
paint?: Record<string, Record<string, unknown>>;
|
|
4715
|
+
layout?: Record<string, Record<string, unknown>>;
|
|
4716
|
+
'osmgl-model3d-key'?: string;
|
|
4717
|
+
[key: string]: unknown;
|
|
4718
|
+
}
|
|
4719
|
+
/** Стиль с признаком v2 (`metadata["osmgl:version"]`). Чистый MapLibre — тоже v2, но без своих полей. */
|
|
4720
|
+
declare function isOsmglV2(value: unknown): boolean;
|
|
4721
|
+
type V1Where = 'field' | 'paint' | 'layout';
|
|
4722
|
+
type V2Where = 'layer' | 'layout' | 'paint';
|
|
4723
|
+
/** Что конвертер не смог перенести: `слой: поле`. */
|
|
4724
|
+
type ConvertReport = string[];
|
|
2016
4725
|
/**
|
|
2017
|
-
*
|
|
2018
|
-
*
|
|
2019
|
-
*
|
|
4726
|
+
* СЛОЙ v1 → v2.
|
|
4727
|
+
*
|
|
4728
|
+
* Подпись: слой, поставленный импортёром MapLibre (`placementMode: maplibre`), остаётся слоем
|
|
4729
|
+
* MapLibre и получает явные значения там, где умолчания v1 и MapLibre расходятся; любой другой — это
|
|
4730
|
+
* своя система подписей (`osmgl-symbol-layout: block`), и его поля переносятся одним
|
|
4731
|
+
* переименованием: умолчания у этой системы свои, и пустое поле значит ровно то же, что в v1.
|
|
2020
4732
|
*/
|
|
2021
|
-
declare
|
|
4733
|
+
declare function layerV1toV2(layer: StyleLayerSpec, style: StyleSpec, report?: ConvertReport): LayerSpecV2;
|
|
2022
4734
|
/**
|
|
2023
|
-
*
|
|
2024
|
-
*
|
|
4735
|
+
* СТИЛЬ v1 → v2. Чистая функция: та же внутренняя модель получается обратно загрузчиком
|
|
4736
|
+
* (`importMapLibreStyle`) — это и есть доказательство «без потерь» (`tests/style-v2.test.mjs`).
|
|
2025
4737
|
*/
|
|
2026
|
-
declare
|
|
2027
|
-
/**
|
|
2028
|
-
|
|
4738
|
+
declare function styleV1toV2(style: StyleSpec, report?: ConvertReport): StyleSpecV2;
|
|
4739
|
+
/**
|
|
4740
|
+
* ОДНО СВОЙСТВО v2 → поля v1. Возвращает список правок (`where`, `key`, `value`), `undefined` у
|
|
4741
|
+
* значения — снять поле. `null` — имя незнакомо. Общее для загрузчика, тем и API карты
|
|
4742
|
+
* (`setPaintProperty('road', 'line-color', …)`).
|
|
4743
|
+
*/
|
|
4744
|
+
declare function propertyV2toV1(type: string, where: V2Where, name: string, value: unknown): {
|
|
4745
|
+
where: V1Where;
|
|
4746
|
+
key: string;
|
|
4747
|
+
value: unknown;
|
|
4748
|
+
}[] | null;
|
|
4749
|
+
/** Внутренняя накладка: то же, что `ThemeSpec`, плюс поля слоя (их v1-темы не правили). */
|
|
4750
|
+
interface ThemeInternal {
|
|
4751
|
+
name: string;
|
|
4752
|
+
background?: string;
|
|
4753
|
+
light?: Partial<LightSpec>;
|
|
4754
|
+
sky?: Partial<SkySpec>;
|
|
4755
|
+
paint?: Record<string, Record<string, unknown>>;
|
|
4756
|
+
layout?: Record<string, Record<string, unknown>>;
|
|
4757
|
+
fields?: Record<string, Record<string, unknown>>;
|
|
4758
|
+
hidden?: string[];
|
|
4759
|
+
model3dKey?: string;
|
|
4760
|
+
}
|
|
4761
|
+
/**
|
|
4762
|
+
* ТЕМА v1 → v2 ПО БАЗОВОМУ СТИЛЮ: ключ `color` значит `fill-color`, `line-color` или `text-color`
|
|
4763
|
+
* смотря по типу слоя, а тип знает только база. Id, которого в базе нет, переводится по имени поля
|
|
4764
|
+
* (если оно однозначно) и попадает в отчёт.
|
|
4765
|
+
*/
|
|
4766
|
+
declare function themeV1toV2(theme: ThemeInternal, base: StyleSpec, report?: ConvertReport): ThemeSpecV2;
|
|
4767
|
+
/**
|
|
4768
|
+
* ТЕМА (v2 или v1) → ВНУТРЕННЯЯ НАКЛАДКА. Ключи разбираются по одному: имя v2 переводится по
|
|
4769
|
+
* таблице, имя v1 принимается как синоним (с одним предупреждением), незнакомое остаётся как есть —
|
|
4770
|
+
* так тема прошлого выпуска, написанная приложением, продолжает работать.
|
|
4771
|
+
*/
|
|
4772
|
+
declare function themeToInternal(theme: Record<string, unknown>, base?: StyleSpec): ThemeInternal;
|
|
4773
|
+
/**
|
|
4774
|
+
* СТИЛЬ v2 → ЧИСТЫЙ MapLibre v8: «Скачать для MapLibre» (§1.4, вопрос 2 §6).
|
|
4775
|
+
*
|
|
4776
|
+
* MapLibre файл со своими полями не откроет — его валидатор отвергает незнакомые свойства и типы
|
|
4777
|
+
* слоёв. Поэтому `osmgl-*` срезаются, а то, у чего в MapLibre есть ближайший аналог, переводится
|
|
4778
|
+
* ПРИБЛИЖЁННО (и попадает в отчёт `report`): поверхность — заливкой её цвета, ссылка на цвет — уже
|
|
4779
|
+
* разрешённым цветом, список шаблонов подписи — `coalesce`, своя блочная раскладка подписи — её
|
|
4780
|
+
* умолчаниями, записанными явно. Основе без адреса (`base`, «тайлы даёт карта») адрес можно дать
|
|
4781
|
+
* опцией `tiles`.
|
|
4782
|
+
*/
|
|
4783
|
+
declare function toMapLibreStyle(v2: StyleSpecV2, opts?: {
|
|
4784
|
+
tiles?: string | string[];
|
|
4785
|
+
}, report?: ConvertReport): Record<string, unknown> & {
|
|
4786
|
+
version: 8;
|
|
4787
|
+
layers: Record<string, unknown>[];
|
|
4788
|
+
};
|
|
2029
4789
|
|
|
2030
4790
|
/**
|
|
2031
4791
|
* Тема — набор правок поверх базового стиля, а не его копия.
|
|
@@ -5036,6 +7796,418 @@ declare class Marker extends Evented<MarkerEvents> {
|
|
|
5036
7796
|
private applyVisibility;
|
|
5037
7797
|
}
|
|
5038
7798
|
|
|
7799
|
+
/**
|
|
7800
|
+
* Тесселяция геометрии, заданной ПОЛЬЗОВАТЕЛЕМ, а не тайлом.
|
|
7801
|
+
*
|
|
7802
|
+
* Отличие от `generators/*` одно, зато принципиальное — система координат.
|
|
7803
|
+
* Тайловая вершина лежит в целых [0..extent] и помещается в Int16; у рантайм-объекта
|
|
7804
|
+
* своего тайла нет, а маршрут через город — это десятки километров, и Int16 дал бы
|
|
7805
|
+
* на них шаг около метра (на z20 это 8 пикселей дрожания).
|
|
7806
|
+
*
|
|
7807
|
+
* Поэтому локальные координаты здесь — **нормализованный меркатор относительно
|
|
7808
|
+
* origin объекта**, во Float32. Смещения порядка 1e-4, мантиссы хватает на доли
|
|
7809
|
+
* миллиметра.
|
|
7810
|
+
*
|
|
7811
|
+
* ЛИНИЯ СТРОИТСЯ ЛЕНТОЙ СО СТЫКАМИ — как в Mapbox (`line_bucket`): направления
|
|
7812
|
+
* и биссектрисы стыков считаются ЗДЕСЬ, на CPU, в двойной точности, а в вершину
|
|
7813
|
+
* кладётся готовый единичный вектор поперёк полотна. Шейдер только умножает его
|
|
7814
|
+
* на полуширину в пикселях.
|
|
7815
|
+
*
|
|
7816
|
+
* Так было не всегда: сначала каждый отрезок рисовался отдельной «капсулой», а
|
|
7817
|
+
* направление считалось в шейдере как `normalize(p1 - p0)`. В тайле это
|
|
7818
|
+
* работает (координаты — целые 0..4096), а у объекта разность соседних точек в
|
|
7819
|
+
* нормализованном меркаторе порядка 1e-6, и на городском маршруте линия
|
|
7820
|
+
* рассыпалась в цепочку точек: отрезок короче собственной полуширины квад не
|
|
7821
|
+
* накрывал. Ещё и стыков у капсул не было — на изломах оставались щели.
|
|
7822
|
+
*
|
|
7823
|
+
* Раскладка вершины ленты:
|
|
7824
|
+
*
|
|
7825
|
+
* a_pos 2 × Float32 off 0 точка оси (локальный меркатор)
|
|
7826
|
+
* a_extrude 2 × Float32 off 8 куда раздувать, единичный (в стыке длиннее — митра)
|
|
7827
|
+
* a_side 1 × Float32 off 16 −1 | 0 | +1 — сторона полотна, 0 в центре скругления
|
|
7828
|
+
* a_dist 1 × Float32 off 20 расстояние вдоль линии, в единицах объекта
|
|
7829
|
+
*/
|
|
7830
|
+
declare const RUNTIME_LINE_STRIDE = 24;
|
|
7831
|
+
declare const RUNTIME_FILL_STRIDE = 8;
|
|
7832
|
+
interface RuntimeMesh {
|
|
7833
|
+
vertices: ArrayBuffer;
|
|
7834
|
+
indices: Uint32Array;
|
|
7835
|
+
vertexCount: number;
|
|
7836
|
+
/** Прозрачность в вершине — у площади с `alphas` (`buildRuntimeArea`); иначе нет. */
|
|
7837
|
+
alphas?: Float32Array;
|
|
7838
|
+
/** Метр трассы в вершине — у площади со `stations` (`buildRuntimeArea`, он же в поле расстояния вершины); иначе нет. */
|
|
7839
|
+
stations?: Float32Array;
|
|
7840
|
+
}
|
|
7841
|
+
/** Путь в локальных координатах: x,y вперемешку. */
|
|
7842
|
+
type LocalPath = number[];
|
|
7843
|
+
/**
|
|
7844
|
+
* Лента линии со стыками и круглыми концами.
|
|
7845
|
+
*
|
|
7846
|
+
* На каждую точку пути кладётся ПАРА вершин по обе стороны оси; соседние пары
|
|
7847
|
+
* сшиваются двумя треугольниками. Куда раздувать вершину — решает биссектриса
|
|
7848
|
+
* соседних отрезков (митра), длина её ограничена `MITER_LIMIT`.
|
|
7849
|
+
*
|
|
7850
|
+
* СТЫКИ СКРУГЛЁННЫЕ (`line-join: round` у Mapbox): на заметном изломе между
|
|
7851
|
+
* концом одного отрезка и началом другого вставляется веер из долек, и угол
|
|
7852
|
+
* получается круглым, а не срезанным. Фаска (одна долька) осталась частным
|
|
7853
|
+
* случаем — ею закрываются пологие изломы, где скругления всё равно не видно.
|
|
7854
|
+
* Концы тоже закрываются веером — получается скруглённый торец, как у маршрута
|
|
7855
|
+
* в любой карте.
|
|
7856
|
+
*/
|
|
7857
|
+
declare function buildRuntimeLine(paths: LocalPath[]): RuntimeMesh | null;
|
|
7858
|
+
/**
|
|
7859
|
+
* Заливка кольцами: первое — внешнее, остальные — дырки.
|
|
7860
|
+
*
|
|
7861
|
+
* Намотку не выправляем: earcut разбирается сам, а порядок вершин в треугольнике
|
|
7862
|
+
* переворачиваем — Y меркатора направлен вниз, и без этого все грани смотрели бы
|
|
7863
|
+
* от камеры (отсечение задних граней у плоских слоёв выключено, но объекты могут
|
|
7864
|
+
* рисоваться и в проходе с отсечением).
|
|
7865
|
+
*/
|
|
7866
|
+
declare function buildRuntimeFill(rings: LocalPath[]): RuntimeMesh | null;
|
|
7867
|
+
|
|
7868
|
+
/**
|
|
7869
|
+
* Рантайм-объекты: то, что кладёт на карту приложение, а не тайлсервер, —
|
|
7870
|
+
* маршрут, зона доставки, трек машины, окружность радиуса.
|
|
7871
|
+
*
|
|
7872
|
+
* Устроены не как источник тайлов, а как отдельный список: этих объектов
|
|
7873
|
+
* единицы, их правят покадрово (машина едет), и гонять их через воркер и LRU
|
|
7874
|
+
* означало бы платить за инфраструктуру, которая здесь ничего не экономит.
|
|
7875
|
+
*
|
|
7876
|
+
* У каждого объекта своё НАЧАЛО КООРДИНАТ — центр его habitat'а в нормализованном
|
|
7877
|
+
* меркаторе. Вершины хранятся относительно него, поэтому во Float32 не теряется
|
|
7878
|
+
* точность даже у маршрута через весь город (см. `mesh.ts`).
|
|
7879
|
+
*/
|
|
7880
|
+
interface ObjectPaint {
|
|
7881
|
+
color?: string;
|
|
7882
|
+
opacity?: number;
|
|
7883
|
+
/** Ширина линии в CSS-пикселях (у линий) или обводки (у полигонов). */
|
|
7884
|
+
width?: number;
|
|
7885
|
+
/** Обводка снизу — рисуется первой и шире, как у дорог в стиле. */
|
|
7886
|
+
strokeColor?: string;
|
|
7887
|
+
strokeWidth?: number;
|
|
7888
|
+
/** Пунктир `[штрих, пропуск]` в пикселях. */
|
|
7889
|
+
dashArray?: [number, number];
|
|
7890
|
+
/** Стрелки направления вдоль линии. */
|
|
7891
|
+
arrow?: boolean;
|
|
7892
|
+
arrowColor?: string;
|
|
7893
|
+
arrowPeriod?: number;
|
|
7894
|
+
arrowSize?: number;
|
|
7895
|
+
/** Сдвиг поперёк линии в пикселях — для двух направлений на одной дороге. */
|
|
7896
|
+
offset?: number;
|
|
7897
|
+
/**
|
|
7898
|
+
* Насколько виден объект ТАМ, ГДЕ ОН ЗА ГЕОМЕТРИЕЙ (0 — не виден вовсе).
|
|
7899
|
+
*
|
|
7900
|
+
* Маршрут лежит на земле и честно скрывается за домами — иначе он летел бы
|
|
7901
|
+
* поверх города. Но тогда в плотной застройке от трассы остаются обрывки, и
|
|
7902
|
+
* куда она идёт, непонятно. «Призрак» — второй, бледный проход поверх зданий
|
|
7903
|
+
* ровно в тех местах, где линия ушла за них: так делают Яндекс и Google.
|
|
7904
|
+
*/
|
|
7905
|
+
ghostOpacity?: number;
|
|
7906
|
+
/**
|
|
7907
|
+
* В чём заданы ширина, шаг и размер стрелок линии: `px` (по умолчанию) — экранные пиксели, `m` —
|
|
7908
|
+
* метры на земле (шевроны ленты по полосам: ширина полосы, а не толщина значка).
|
|
7909
|
+
*/
|
|
7910
|
+
units?: 'px' | 'm';
|
|
7911
|
+
}
|
|
7912
|
+
interface MapObjectOptions extends ObjectPaint {
|
|
7913
|
+
/** Порядок отрисовки среди рантайм-объектов. Больше — выше. */
|
|
7914
|
+
zIndex?: number;
|
|
7915
|
+
/** Высота над землёй в метрах: маршрут на эстакаде, метка на крыше. */
|
|
7916
|
+
altitude?: number;
|
|
7917
|
+
/**
|
|
7918
|
+
* ПОДЪЁМ ПОД ВЕРШИНОЙ, метры, сверх `altitude`: отметка полотна в точке `(lng, lat)` — эстакада под
|
|
7919
|
+
* трассой, съезд с неё. Своя у каждой вершины (по точке оси линии, по углу заливки), поэтому линия и
|
|
7920
|
+
* стрелка поворота идут по настилу и по склону подхода, а не висят на одной высоте над всей длиной.
|
|
7921
|
+
* Вне эстакады — 0: объект лежит на асфальте. Считается при сборке буферов (`ObjectManager.groundOf`),
|
|
7922
|
+
* сменилась функция — `setLiftAt`.
|
|
7923
|
+
*/
|
|
7924
|
+
liftAt?: LiftAt | null;
|
|
7925
|
+
/** С какого зума объект виден (как `minzoom` слоя): ниже — не рисуется и не ловит клик. */
|
|
7926
|
+
minZoom?: number;
|
|
7927
|
+
/**
|
|
7928
|
+
* МНОЖИТЕЛЬ ПРОЗРАЧНОСТИ в кадре (0…1, по умолчанию 1): цвет объекта умножается на него при отрисовке,
|
|
7929
|
+
* геометрия не пересобирается; 0 — объект не рисуется. Можно менять каждым кадром — так лента по полосам
|
|
7930
|
+
* и куски линии под ней сменяют друг друга переходом (`RibbonBlend`).
|
|
7931
|
+
*/
|
|
7932
|
+
fade?: number;
|
|
7933
|
+
/**
|
|
7934
|
+
* РАСТВОРЕНИЕ ВДОЛЬ ТРАССЫ ПОЗАДИ МАШИНЫ (`AlongFade`): множитель прозрачности по метру трассы точки —
|
|
7935
|
+
* в шейдере, по униформу; метр машины можно менять каждым кадром без пересборки геометрии. Метр точки —
|
|
7936
|
+
* у площади из `RouteAreaOptions.stations`, у линии — `base` плюс расстояние вдоль неё. Нет — не растворяется.
|
|
7937
|
+
*/
|
|
7938
|
+
along?: AlongFade | null;
|
|
7939
|
+
visible?: boolean;
|
|
7940
|
+
/** Что угодно прикладное — вернётся при клике. */
|
|
7941
|
+
userData?: Record<string, unknown>;
|
|
7942
|
+
/** Своё имя; иначе будет сгенерировано. */
|
|
7943
|
+
id?: string;
|
|
7944
|
+
}
|
|
7945
|
+
/** Одна порция геометрии: чем рисовать и какой краской. */
|
|
7946
|
+
interface ObjectPart {
|
|
7947
|
+
kind: 'fill' | 'line';
|
|
7948
|
+
mesh: RuntimeMesh;
|
|
7949
|
+
color: [number, number, number, number];
|
|
7950
|
+
/** Ширина в CSS-пикселях; только для `line`. */
|
|
7951
|
+
width: number;
|
|
7952
|
+
dashArray?: [number, number];
|
|
7953
|
+
arrow?: boolean;
|
|
7954
|
+
arrowColor?: [number, number, number, number];
|
|
7955
|
+
arrowPeriod?: number;
|
|
7956
|
+
arrowSize?: number;
|
|
7957
|
+
offset?: number;
|
|
7958
|
+
/**
|
|
7959
|
+
* Цвет В ВЕРШИНЕ (прямой, не домноженный), по 4 числа на вершину меша; `color` тогда — множитель
|
|
7960
|
+
* (берётся только его альфа: прозрачность объекта и призрака). Так рисуется линия с плавными
|
|
7961
|
+
* стыками пробок одним мешем — без перекрытия кусков на стыках.
|
|
7962
|
+
*/
|
|
7963
|
+
colors?: Float32Array;
|
|
7964
|
+
/**
|
|
7965
|
+
* ПЛОЩАДЬ ПРОГРАММОЙ ЛИНИИ (`RouteArea`): внутренность красится целиком, кромки — сглаживающей
|
|
7966
|
+
* полосой, как край линии маршрута. Полуширина — полпикселя, сдвига и рисунка нет.
|
|
7967
|
+
*/
|
|
7968
|
+
area?: boolean;
|
|
7969
|
+
/** Ширина, шаг и размер стрелок — в метрах на земле (`ObjectPaint.units = 'm'`). */
|
|
7970
|
+
metres?: boolean;
|
|
7971
|
+
}
|
|
7972
|
+
/** Отметка полотна в точке, метры (`MapObjectOptions.liftAt`). */
|
|
7973
|
+
type LiftAt = (lng: number, lat: number) => number;
|
|
7974
|
+
/**
|
|
7975
|
+
* Растворение вдоль трассы (`MapObjectOptions.along`): лента по полосам позади машины не обрывается на её
|
|
7976
|
+
* метре, а гаснет на `length` метров (синяя, `dir` +1) и проявляется серой пройденной (`dir` −1).
|
|
7977
|
+
*/
|
|
7978
|
+
interface AlongFade {
|
|
7979
|
+
/** Метр машины. */
|
|
7980
|
+
at: number;
|
|
7981
|
+
/** Длина растворения позади машины, метры (> 0). */
|
|
7982
|
+
length: number;
|
|
7983
|
+
/** +1 — видно впереди машины, гаснет позади; −1 — наоборот. */
|
|
7984
|
+
dir: 1 | -1;
|
|
7985
|
+
/** У линии: метр её первой точки (метр точки = `base` + расстояние вдоль линии). У площади не нужен. */
|
|
7986
|
+
base?: number;
|
|
7987
|
+
/**
|
|
7988
|
+
* У линии: метров на единицу её длины (меркатор, мир = 1). Нет — длина окружности на широте объекта: на
|
|
7989
|
+
* длинном куске это расходится с мерой трассы на десятки метров, поэтому линия маршрута задаёт масштаб
|
|
7990
|
+
* сама — по точным метрам концов куска (`routeLineAlong`).
|
|
7991
|
+
*/
|
|
7992
|
+
scale?: number;
|
|
7993
|
+
}
|
|
7994
|
+
/**
|
|
7995
|
+
* Множитель растворения в точке с метром `station` — ТО ЖЕ, что считает шейдер (`OBJECT_LINE_FRAG`, `u_along`):
|
|
7996
|
+
* доля `k` = smoothstep от «машина − длина» (0) до машины (1); +1 — `k`, −1 — `1 − k`. Для тестов и сверки портов.
|
|
7997
|
+
*/
|
|
7998
|
+
declare function alongFadeFactor(along: AlongFade, station: number): number;
|
|
7999
|
+
declare abstract class MapObject {
|
|
8000
|
+
readonly id: string;
|
|
8001
|
+
zIndex: number;
|
|
8002
|
+
altitude: number;
|
|
8003
|
+
visible: boolean;
|
|
8004
|
+
userData: Record<string, unknown>;
|
|
8005
|
+
/** Подъём под вершиной (`MapObjectOptions.liftAt`); `null` — нет. */
|
|
8006
|
+
private _liftAt;
|
|
8007
|
+
/** С какого зума объект виден (`MapObjectOptions.minZoom`). */
|
|
8008
|
+
minZoom: number;
|
|
8009
|
+
/** Множитель прозрачности в кадре (`MapObjectOptions.fade`). */
|
|
8010
|
+
fade: number;
|
|
8011
|
+
/** Растворение вдоль трассы (`MapObjectOptions.along`); можно менять каждым кадром. */
|
|
8012
|
+
along: AlongFade | null;
|
|
8013
|
+
/** Начало локальных координат — нормализованный меркатор. */
|
|
8014
|
+
originX: number;
|
|
8015
|
+
originY: number;
|
|
8016
|
+
/**
|
|
8017
|
+
* Насколько объект виден там, где он за геометрией. Читает менеджер: проход
|
|
8018
|
+
* призрака решает по нему, рисовать ли объект второй раз (см. `ObjectPaint`).
|
|
8019
|
+
*/
|
|
8020
|
+
get ghostOpacity(): number;
|
|
8021
|
+
protected paint: ObjectPaint;
|
|
8022
|
+
/** Геометрию надо пересобрать (и перезалить в GPU). */
|
|
8023
|
+
private _revision;
|
|
8024
|
+
constructor(options: MapObjectOptions);
|
|
8025
|
+
/** Подъём под вершиной, метры (`MapObjectOptions.liftAt`); `null` — объект на земле. */
|
|
8026
|
+
get liftAt(): LiftAt | null;
|
|
8027
|
+
/** Другая отметка полотна (сцена дорог перестроена) — высоты вершин пересчитываются. */
|
|
8028
|
+
setLiftAt(liftAt: LiftAt | null): this;
|
|
8029
|
+
private _liftRevision;
|
|
8030
|
+
/**
|
|
8031
|
+
* Ревизия ОТМЕТКИ ПОЛОТНА (26.10.2026): новая высота под той же формой (`setLiftAt`). Холодный старт NaviGram на порте:
|
|
8032
|
+
* пачки тайлов сетки детальных дорог во время наезда камеры ведения перекладывали высоту всех объектов маршрута, и
|
|
8033
|
+
* кадр пересобирал их целиком — 50–140 мс раз в 0,3 с (Redmi, `--es slow`).
|
|
8034
|
+
*/
|
|
8035
|
+
get liftRevision(): number;
|
|
8036
|
+
/** Меняется при любой правке — по нему менеджер понимает, что буферы устарели. */
|
|
8037
|
+
get revision(): number;
|
|
8038
|
+
protected invalidate(): void;
|
|
8039
|
+
/** Правка оформления без пересборки геометрии — но буферы всё равно общие. */
|
|
8040
|
+
setPaint(paint: ObjectPaint): this;
|
|
8041
|
+
/** Точки объекта в ЭКРАННЫХ координатах нужны и пикингу, и отладке. */
|
|
8042
|
+
abstract rings(): LngLatLike[][];
|
|
8043
|
+
abstract build(): ObjectPart[];
|
|
8044
|
+
/** Попадание точки экрана в объект. `project` возвращает null за камерой. */
|
|
8045
|
+
abstract hitTest(point: {
|
|
8046
|
+
x: number;
|
|
8047
|
+
y: number;
|
|
8048
|
+
}, project: (lng: number, lat: number, alt: number) => {
|
|
8049
|
+
x: number;
|
|
8050
|
+
y: number;
|
|
8051
|
+
} | null, tolerancePx: number): boolean;
|
|
8052
|
+
/**
|
|
8053
|
+
* Начало координат ставим в центр рамки, а не в первую точку: у кольцевого
|
|
8054
|
+
* маршрута первая точка может лежать на краю, и смещения удвоятся зря.
|
|
8055
|
+
*/
|
|
8056
|
+
protected setOriginFromCoords(coords: LngLatLike[][]): void;
|
|
8057
|
+
protected toLocal(ring: LngLatLike[]): LocalPath;
|
|
8058
|
+
protected color(key: 'color' | 'strokeColor' | 'arrowColor', fallback: string): [number, number, number, number];
|
|
8059
|
+
/** Общие для линий поля оформления — чтобы не повторять их в каждом объекте. */
|
|
8060
|
+
protected linePaint(part: ObjectPart): ObjectPart;
|
|
8061
|
+
}
|
|
8062
|
+
/**
|
|
8063
|
+
* Кусок линии со своим цветом: с точки `at` и до `at` следующего куска.
|
|
8064
|
+
*
|
|
8065
|
+
* Так задаётся раскраска маршрута по пробкам. Хранить цвет на каждой точке было
|
|
8066
|
+
* бы и длиннее, и бессмысленно: цвет меняется на границах дорог, а не в каждой
|
|
8067
|
+
* вершине геометрии.
|
|
8068
|
+
*/
|
|
8069
|
+
interface PolylineSegment {
|
|
8070
|
+
/** Индекс первой точки куска в `coordinates`. */
|
|
8071
|
+
at: number;
|
|
8072
|
+
color: string;
|
|
8073
|
+
}
|
|
8074
|
+
interface PolylineOptions extends MapObjectOptions {
|
|
8075
|
+
coordinates: LngLatLike[];
|
|
8076
|
+
/**
|
|
8077
|
+
* Куски со своим цветом. Пусто — линия одноцветная (`paint.color`).
|
|
8078
|
+
* Первый кусок обязан начинаться с нуля; куски идут по возрастанию `at`.
|
|
8079
|
+
*/
|
|
8080
|
+
segments?: PolylineSegment[];
|
|
8081
|
+
/**
|
|
8082
|
+
* ПЛАВНЫЕ СТЫКИ КУСКОВ: ширина перехода цвета на стыке, метры (0 — ступенькой, как раньше).
|
|
8083
|
+
* Переход линейный, по центру на точке стыка; не шире половины любого из соседних кусков.
|
|
8084
|
+
* Линия тогда строится ОДНИМ мешем с цветом в вершине: на стыке нет ни перекрытия полупрозрачных
|
|
8085
|
+
* кусков, ни шва, а шевроны идут без сбоя фазы.
|
|
8086
|
+
*/
|
|
8087
|
+
segmentBlend?: number;
|
|
8088
|
+
}
|
|
8089
|
+
/**
|
|
8090
|
+
* Ломаная: маршрут, трек, граница коридора.
|
|
8091
|
+
*
|
|
8092
|
+
* Обводка (`strokeColor`) рисуется отдельной, более широкой линией ПОД основной —
|
|
8093
|
+
* тем же приёмом, что дороги в стиле. Отдельного прохода она не требует, потому
|
|
8094
|
+
* что рантайм-объекты и так рисуются по порядку.
|
|
8095
|
+
*/
|
|
8096
|
+
declare class Polyline extends MapObject {
|
|
8097
|
+
private coordinates;
|
|
8098
|
+
private segments;
|
|
8099
|
+
private segmentBlend;
|
|
8100
|
+
constructor(options: PolylineOptions);
|
|
8101
|
+
/** Ширина плавного стыка кусков, метры (0 — ступенькой). */
|
|
8102
|
+
setSegmentBlend(meters: number): this;
|
|
8103
|
+
setCoordinates(coordinates: LngLatLike[]): this;
|
|
8104
|
+
/** Перекрасить куски линии, не трогая геометрию. Пусто — снова один цвет. */
|
|
8105
|
+
setSegments(segments: PolylineSegment[]): this;
|
|
8106
|
+
getCoordinates(): LngLatLike[];
|
|
8107
|
+
rings(): LngLatLike[][];
|
|
8108
|
+
build(): ObjectPart[];
|
|
8109
|
+
/**
|
|
8110
|
+
* Куски в виде диапазонов точек. Пусто — линия одноцветная.
|
|
8111
|
+
*
|
|
8112
|
+
* Мусор во входных данных гасим здесь, а не в отрисовке: куски приходят из
|
|
8113
|
+
* ответа сервиса, и один сбитый индекс не должен ронять всю линию. Куски вне
|
|
8114
|
+
* диапазона и пустые отбрасываются, порядок восстанавливается сортировкой.
|
|
8115
|
+
*/
|
|
8116
|
+
private colorRuns;
|
|
8117
|
+
hitTest(point: {
|
|
8118
|
+
x: number;
|
|
8119
|
+
y: number;
|
|
8120
|
+
}, project: (lng: number, lat: number, alt: number) => {
|
|
8121
|
+
x: number;
|
|
8122
|
+
y: number;
|
|
8123
|
+
} | null, tolerancePx: number): boolean;
|
|
8124
|
+
}
|
|
8125
|
+
interface PolygonOptions extends MapObjectOptions {
|
|
8126
|
+
/** Кольца: первое внешнее, остальные — дырки. */
|
|
8127
|
+
coordinates: LngLatLike[][];
|
|
8128
|
+
}
|
|
8129
|
+
declare class Polygon extends MapObject {
|
|
8130
|
+
private coordinates;
|
|
8131
|
+
constructor(options: PolygonOptions);
|
|
8132
|
+
setCoordinates(coordinates: LngLatLike[][]): this;
|
|
8133
|
+
rings(): LngLatLike[][];
|
|
8134
|
+
build(): ObjectPart[];
|
|
8135
|
+
hitTest(point: {
|
|
8136
|
+
x: number;
|
|
8137
|
+
y: number;
|
|
8138
|
+
}, project: (lng: number, lat: number, alt: number) => {
|
|
8139
|
+
x: number;
|
|
8140
|
+
y: number;
|
|
8141
|
+
} | null): boolean;
|
|
8142
|
+
}
|
|
8143
|
+
interface RouteAreaOptions extends MapObjectOptions {
|
|
8144
|
+
/** Кольца: первое внешнее, остальные — дырки (замыкающая точка не обязательна). */
|
|
8145
|
+
coordinates: LngLatLike[][];
|
|
8146
|
+
/**
|
|
8147
|
+
* Какие кромки сглаживать: `feather[r][i]` — кромка `i → i+1` кольца `r` (без замыкающей точки).
|
|
8148
|
+
* Нет — все. Шов с соседним куском той же площади не сглаживается: там нет края.
|
|
8149
|
+
*/
|
|
8150
|
+
feather?: boolean[][];
|
|
8151
|
+
/**
|
|
8152
|
+
* Прозрачность В ВЕРШИНЕ кольца: `alphas[r][i]` — множитель для точки `i` кольца `r` (форма — как у
|
|
8153
|
+
* `coordinates`). Между вершинами GPU смешивает линейно. Нет — площадь одной прозрачности. Так лента
|
|
8154
|
+
* по полосам растворяется у концов, где её сменяет линия маршрута (`fadeRibbonArea`).
|
|
8155
|
+
*/
|
|
8156
|
+
alphas?: number[][];
|
|
8157
|
+
/**
|
|
8158
|
+
* МЕТР ТРАССЫ В ВЕРШИНЕ кольца (форма — как у `coordinates`): по нему площадь растворяется позади машины
|
|
8159
|
+
* (`along`). Между вершинами GPU смешивает метр линейно, а гладкую ступеньку считает в каждом пикселе.
|
|
8160
|
+
*/
|
|
8161
|
+
stations?: number[][];
|
|
8162
|
+
}
|
|
8163
|
+
/**
|
|
8164
|
+
* ПЛОЩАДЬ, НАРИСОВАННАЯ ТАК ЖЕ, КАК ЛИНИЯ МАРШРУТА: та же программа (`OBJECT_LINE_*`), тот же проход,
|
|
8165
|
+
* тот же тест и сдвиг глубины, та же высота вершин (`liftAt`), то же сглаживание края и тот же порядок
|
|
8166
|
+
* (`zIndex`). Так рисуются лента по полосам и стрелки поворотов — они лежат с линией одной краской.
|
|
8167
|
+
*/
|
|
8168
|
+
declare class RouteArea extends MapObject {
|
|
8169
|
+
private coordinates;
|
|
8170
|
+
private feather;
|
|
8171
|
+
private alphas;
|
|
8172
|
+
private stations;
|
|
8173
|
+
constructor(options: RouteAreaOptions);
|
|
8174
|
+
setCoordinates(coordinates: LngLatLike[][], feather?: boolean[][] | null, alphas?: number[][] | null, stations?: number[][] | null): this;
|
|
8175
|
+
rings(): LngLatLike[][];
|
|
8176
|
+
build(): ObjectPart[];
|
|
8177
|
+
hitTest(point: {
|
|
8178
|
+
x: number;
|
|
8179
|
+
y: number;
|
|
8180
|
+
}, project: (lng: number, lat: number, alt: number) => {
|
|
8181
|
+
x: number;
|
|
8182
|
+
y: number;
|
|
8183
|
+
} | null): boolean;
|
|
8184
|
+
}
|
|
8185
|
+
interface CircleOptions$1 extends MapObjectOptions {
|
|
8186
|
+
center: LngLatLike;
|
|
8187
|
+
/** Радиус в МЕТРАХ на земле. */
|
|
8188
|
+
radius: number;
|
|
8189
|
+
/** Число сегментов; по умолчанию подбирается по радиусу. */
|
|
8190
|
+
segments?: number;
|
|
8191
|
+
}
|
|
8192
|
+
/**
|
|
8193
|
+
* Круг заданного радиуса в метрах — зона доставки, точность позиции, радиус поиска.
|
|
8194
|
+
*
|
|
8195
|
+
* Считается прямо в меркаторе: проекция конформна, поэтому круг на местности
|
|
8196
|
+
* остаётся кругом на карте, надо лишь взять масштаб на широте центра. Для радиусов
|
|
8197
|
+
* городского масштаба (до десятков километров) расхождение с геодезической
|
|
8198
|
+
* окружностью меньше толщины линии.
|
|
8199
|
+
*/
|
|
8200
|
+
declare class Circle extends Polygon {
|
|
8201
|
+
constructor(options: CircleOptions$1);
|
|
8202
|
+
}
|
|
8203
|
+
type Projected = {
|
|
8204
|
+
x: number;
|
|
8205
|
+
y: number;
|
|
8206
|
+
};
|
|
8207
|
+
declare function distToSegment(p: Projected, a: Projected, b: Projected): number;
|
|
8208
|
+
/** Классический ray casting: считаем пересечения луча вправо от точки. */
|
|
8209
|
+
declare function pointInRing(p: Projected, ring: Projected[]): boolean;
|
|
8210
|
+
|
|
5039
8211
|
declare class ObjectManager {
|
|
5040
8212
|
/**
|
|
5041
8213
|
* Высота земли в точке нормализованного меркатора — её даёт рельеф.
|
|
@@ -5134,6 +8306,447 @@ declare class ObjectManager {
|
|
|
5134
8306
|
destroy(): void;
|
|
5135
8307
|
}
|
|
5136
8308
|
|
|
8309
|
+
/**
|
|
8310
|
+
* Разбор GLB (двоичный glTF 2.0).
|
|
8311
|
+
*
|
|
8312
|
+
* Своё, а не готовая библиотека, по той же причине, что и всё остальное в этом
|
|
8313
|
+
* движке: нам нужна ровно та часть формата, которая доедет до нашего рендера, —
|
|
8314
|
+
* позиции, нормали, координаты текстуры, индексы, базовый цвет и его текстура.
|
|
8315
|
+
* Полноценный загрузчик тащит за собой анимации, скиннинг, KHR-расширения и
|
|
8316
|
+
* декодеры сжатия; всё это здесь пока некуда девать.
|
|
8317
|
+
*
|
|
8318
|
+
* meshopt (`EXT_meshopt_compression`) поддержан: именно в нём лежат ВСЕ наши
|
|
8319
|
+
* боевые ассеты — сервис Objects3D прогоняет загруженный glTF через gltfpack
|
|
8320
|
+
* (`-cc`, два уровня LOD), и без декодера с сервера не читается ни одна модель.
|
|
8321
|
+
* Декодер берётся из библиотеки `meshoptimizer` (MIT, автор формата) — писать
|
|
8322
|
+
* свой значит переписывать эталонную реализацию ради тех же байтов.
|
|
8323
|
+
* Вместе с ним приходит и КВАНТИЗАЦИЯ (`KHR_mesh_quantization`): позиции едут
|
|
8324
|
+
* целыми с масштабом в матрице узла, нормали и развёртка — нормализованными
|
|
8325
|
+
* целыми, поэтому аксессоры обязаны знать про `normalized`.
|
|
8326
|
+
*
|
|
8327
|
+
* Чего сознательно НЕТ:
|
|
8328
|
+
* - Draco — свой декодер, а наши ассеты в него не пакуются;
|
|
8329
|
+
* - анимации и скиннинг;
|
|
8330
|
+
* - PBR сверх базового цвета: металличность и шероховатость движок пока не
|
|
8331
|
+
* использует, а рисовать их «наполовину» хуже, чем не рисовать.
|
|
8332
|
+
*
|
|
8333
|
+
* Иерархия узлов СХЛОПЫВАЕТСЯ на разборе: каждый примитив получает свою мировую
|
|
8334
|
+
* матрицу и уезжает в общий буфер. Держать дерево незачем — анимации нет, а
|
|
8335
|
+
* лишние вызовы отрисовки на узел дороже одного большого буфера.
|
|
8336
|
+
*/
|
|
8337
|
+
/** Байт на вершину: позиция 3×f32, нормаль 3×f32, текстура 2×f32. */
|
|
8338
|
+
declare const MODEL_VERTEX_STRIDE = 32;
|
|
8339
|
+
interface ModelPrimitive {
|
|
8340
|
+
/** Смещение в общем индексном буфере и число индексов. */
|
|
8341
|
+
indexOffset: number;
|
|
8342
|
+
indexCount: number;
|
|
8343
|
+
/** Базовый цвет материала, RGBA 0..1. */
|
|
8344
|
+
baseColor: [number, number, number, number];
|
|
8345
|
+
/**
|
|
8346
|
+
* СОБСТВЕННОЕ свечение материала: `emissiveFactor` × `emissiveStrength`.
|
|
8347
|
+
*
|
|
8348
|
+
* Прибавляется к освещённому цвету и НЕ умножается на свет сцены — в этом весь
|
|
8349
|
+
* смысл: поверхность светится сама. Художник задаёт им «нижний порог» яркости,
|
|
8350
|
+
* чтобы объект не проваливался в черноту, а окна и вывески читались ночью.
|
|
8351
|
+
*
|
|
8352
|
+
* В наших моделях это заполнено осмысленно: у стены 0.22, у двери 0.5, у окна
|
|
8353
|
+
* 0.12, у вывески 0.3. Раньше мы читали из материала только базовый цвет, и всё
|
|
8354
|
+
* это терялось — модель выходила темнее задуманного, а ночью гасла совсем.
|
|
8355
|
+
* Тот же приём у Mapbox называется `emissive-strength`.
|
|
8356
|
+
*/
|
|
8357
|
+
emissive: [number, number, number];
|
|
8358
|
+
/**
|
|
8359
|
+
* Металличность и шероховатость — по ним считается отражение.
|
|
8360
|
+
*
|
|
8361
|
+
* ОТСТУПЛЕНИЕ ОТ СПЕЦИФИКАЦИИ, и оно намеренное. По стандарту оба значения по умолчанию равны
|
|
8362
|
+
* ЕДИНИЦЕ, то есть материал без разметки — это «идеально шероховатый металл». На практике так
|
|
8363
|
+
* не бывает: экспортёры просто не пишут поля, которых художник не трогал. В библиотеке карты у
|
|
8364
|
+
* дворца два материала из трёх именно такие, и буквальное чтение стандарта делало из белого
|
|
8365
|
+
* камня чёрный металл.
|
|
8366
|
+
*
|
|
8367
|
+
* Поэтому правило такое: если НЕ ЗАДАНО НИ ОДНО из полей — материал считается матовым
|
|
8368
|
+
* диэлектриком (0 и 1), то есть ровно тем, чем он выглядит. Стоит указать хотя бы одно —
|
|
8369
|
+
* работают умолчания стандарта, и автор получает ровно то, что записал.
|
|
8370
|
+
*/
|
|
8371
|
+
metallic: number;
|
|
8372
|
+
roughness: number;
|
|
8373
|
+
/** Индекс изображения в `images` или -1. */
|
|
8374
|
+
texture: number;
|
|
8375
|
+
/** Двусторонний материал — отсечение граней выключается. */
|
|
8376
|
+
doubleSided: boolean;
|
|
8377
|
+
/**
|
|
8378
|
+
* Полупрозрачный материал (`alphaMode: BLEND`).
|
|
8379
|
+
*
|
|
8380
|
+
* Различать обязательно: в моделях сплошь и рядом лежит «подложка-тень» —
|
|
8381
|
+
* плоскость под объектом с полупрозрачной текстурой. Нарисованная непрозрачно,
|
|
8382
|
+
* она выглядит чёрной кляксой (ровно это и было видно под машиной), а в карту
|
|
8383
|
+
* теней такую плоскость пускать нельзя вовсе.
|
|
8384
|
+
*/
|
|
8385
|
+
blend: boolean;
|
|
8386
|
+
/** Порог отсечения для `alphaMode: MASK`. */
|
|
8387
|
+
alphaCutoff: number;
|
|
8388
|
+
/**
|
|
8389
|
+
* Узел, который двигает этот примитив, или −1.
|
|
8390
|
+
*
|
|
8391
|
+
* У неподвижных примитивов преобразование узла ЗАПЕЧЕНО в позиции (так дешевле
|
|
8392
|
+
* всего: один буфер, один вызов). У подвижных запечь нечего — их матрица
|
|
8393
|
+
* меняется каждый кадр, — поэтому позиции хранятся в системе самого узла, а
|
|
8394
|
+
* матрицу даёт `Model.nodeMatrix`.
|
|
8395
|
+
*/
|
|
8396
|
+
node: number;
|
|
8397
|
+
}
|
|
8398
|
+
/** Дорожка одного свойства узла: когда и во что оно превращается. */
|
|
8399
|
+
interface AnimChannel {
|
|
8400
|
+
path: 'translation' | 'rotation' | 'scale';
|
|
8401
|
+
/** Моменты времени в секундах. */
|
|
8402
|
+
times: Float32Array;
|
|
8403
|
+
/** Значения подряд: 3 числа на кадр у сдвига и масштаба, 4 у кватерниона. */
|
|
8404
|
+
values: Float32Array;
|
|
8405
|
+
/** Ступенькой, а не линейно. */
|
|
8406
|
+
step: boolean;
|
|
8407
|
+
}
|
|
8408
|
+
/** Подвижный узел: неизменная часть цепочки предков + его собственные дорожки. */
|
|
8409
|
+
interface AnimNode {
|
|
8410
|
+
/**
|
|
8411
|
+
* Ближайший подвижный ПРЕДОК или −1.
|
|
8412
|
+
*
|
|
8413
|
+
* Без него анимация предка теряется: у клипа с подъёмом и разворотом это два
|
|
8414
|
+
* разных узла (верхний поднимает, нижний вертит), и запомни мы только
|
|
8415
|
+
* статическую матрицу предков — объект остался бы вертеться на месте, не
|
|
8416
|
+
* поднимаясь. Матрица подвижного узла поэтому собирается по цепочке.
|
|
8417
|
+
*/
|
|
8418
|
+
parentNode: number;
|
|
8419
|
+
/** Статическая часть цепочки — от подвижного предка (не включая) до этого узла. */
|
|
8420
|
+
parent: Mat4;
|
|
8421
|
+
/** Значения узла без анимации: тем, чего нет в клипе, остаётся своё. */
|
|
8422
|
+
base: {
|
|
8423
|
+
t: [number, number, number];
|
|
8424
|
+
r: [number, number, number, number];
|
|
8425
|
+
s: [number, number, number];
|
|
8426
|
+
};
|
|
8427
|
+
channels: AnimChannel[];
|
|
8428
|
+
}
|
|
8429
|
+
interface ModelAnimation {
|
|
8430
|
+
/** Длительность клипа в секундах — по ней время заворачивается в цикл. */
|
|
8431
|
+
duration: number;
|
|
8432
|
+
nodes: Map<number, AnimNode>;
|
|
8433
|
+
}
|
|
8434
|
+
/**
|
|
8435
|
+
* Источник света из `KHR_lights_punctual` — то, чем художник рисует ночную подсветку объекта.
|
|
8436
|
+
*
|
|
8437
|
+
* Координаты и радиус — В ПРОСТРАНСТВЕ МОДЕЛИ, там же, где лежат вершины. Это не мелочь: модель
|
|
8438
|
+
* ставится на карту своей матрицей, и переводить светильники в мировые координаты пришлось бы на
|
|
8439
|
+
* каждый экземпляр. В пространстве модели они общие для всех экземпляров одного файла, и шейдер
|
|
8440
|
+
* считает освещение прямо там.
|
|
8441
|
+
*/
|
|
8442
|
+
interface ModelLight {
|
|
8443
|
+
/** `directional` держим ради полноты: свет сцены у нас свой, и такой источник шейдер пропускает. */
|
|
8444
|
+
type: 'point' | 'spot' | 'directional';
|
|
8445
|
+
color: [number, number, number];
|
|
8446
|
+
/** Кандела у точечного и прожектора, люкс у направленного — как в спецификации. */
|
|
8447
|
+
intensity: number;
|
|
8448
|
+
/** Радиус влияния в единицах модели; 0 — не ограничен. */
|
|
8449
|
+
range: number;
|
|
8450
|
+
position: [number, number, number];
|
|
8451
|
+
/** Куда светит прожектор: −Z узла, приведённая к единичной длине. */
|
|
8452
|
+
direction: [number, number, number];
|
|
8453
|
+
/** Косинусы углов конуса: внутри `cosInner` светит в полную силу, за `cosOuter` не светит вовсе. */
|
|
8454
|
+
cosInner: number;
|
|
8455
|
+
cosOuter: number;
|
|
8456
|
+
}
|
|
8457
|
+
interface ModelMesh {
|
|
8458
|
+
vertices: ArrayBuffer;
|
|
8459
|
+
indices: Uint32Array;
|
|
8460
|
+
primitives: ModelPrimitive[];
|
|
8461
|
+
/** Картинки базового цвета в виде байтов файла (PNG/JPEG) — декодирует уже GPU-слой. */
|
|
8462
|
+
images: Uint8Array[];
|
|
8463
|
+
/** Габариты в единицах модели (обычно метры) — по ним считается масштаб на карте. */
|
|
8464
|
+
min: [number, number, number];
|
|
8465
|
+
max: [number, number, number];
|
|
8466
|
+
/** Анимация узлов; null — модель неподвижна. */
|
|
8467
|
+
animation: ModelAnimation | null;
|
|
8468
|
+
/** Собственная подсветка объекта из `KHR_lights_punctual`. Пусто у моделей без неё. */
|
|
8469
|
+
lights: ModelLight[];
|
|
8470
|
+
}
|
|
8471
|
+
/**
|
|
8472
|
+
* Разбор GLB, в том числе meshopt-сжатого.
|
|
8473
|
+
*
|
|
8474
|
+
* Асинхронный, потому что декодер meshopt это WebAssembly: до первого разбора
|
|
8475
|
+
* его надо инстанцировать. Ждём мы это ровно один раз на страницу.
|
|
8476
|
+
*/
|
|
8477
|
+
declare function parseGlbAsync(buffer: ArrayBuffer): Promise<ModelMesh>;
|
|
8478
|
+
declare function parseGlb(buffer: ArrayBuffer): ModelMesh;
|
|
8479
|
+
|
|
8480
|
+
/**
|
|
8481
|
+
* 3D-модель на карте: glTF/GLB по координате.
|
|
8482
|
+
*
|
|
8483
|
+
* Главное требование к этой подсистеме было не «уметь glTF», а **жить в одной
|
|
8484
|
+
* сцене со зданиями**: модель обязана отбрасывать тень на дом и получать тень от
|
|
8485
|
+
* него. Поэтому отдельного прохода теней у моделей нет — они идут в тот же
|
|
8486
|
+
* `renderShadowMap`, что и экструзия. Второй shadow-map мы уже пробовали в
|
|
8487
|
+
* `maps3d-web` и уронили этим кадр (память `maps3d-object-shadows`).
|
|
8488
|
+
*/
|
|
8489
|
+
interface ModelOptions {
|
|
8490
|
+
/** Адрес .glb. Обычный glTF с внешними файлами не поддерживается. */
|
|
8491
|
+
url: string;
|
|
8492
|
+
/**
|
|
8493
|
+
* Своя доставка байтов вместо простого `fetch(url)`.
|
|
8494
|
+
*
|
|
8495
|
+
* Нужна ассетам Objects3D: перед разбором у них кеш в IndexedDB, запрос
|
|
8496
|
+
* ключа и расшифровка AES-GCM. Знание об этом сервисе модели ни к чему —
|
|
8497
|
+
* ей нужен GLB, а откуда он взялся, решает вызывающий. `url` при этом
|
|
8498
|
+
* остаётся: он идёт в сообщения об ошибках.
|
|
8499
|
+
*/
|
|
8500
|
+
fetchBytes?: () => Promise<ArrayBuffer>;
|
|
8501
|
+
coordinates: LngLatLike;
|
|
8502
|
+
/** Высота над землёй, метры. */
|
|
8503
|
+
altitude?: number;
|
|
8504
|
+
/**
|
|
8505
|
+
* Множитель к единицам модели.
|
|
8506
|
+
*
|
|
8507
|
+
* Единицы у моделей какие угодно: в наборе Khronos ToyCar имеет габарит 7 см,
|
|
8508
|
+
* а Fox — 155 «метров». Приводить их к общему знаменателю на глаз бессмысленно,
|
|
8509
|
+
* поэтому масштаб — обязанность приложения. Помогает `fitHeight`.
|
|
8510
|
+
*/
|
|
8511
|
+
scale?: number;
|
|
8512
|
+
/** Подогнать масштаб так, чтобы высота модели стала такой, метры. */
|
|
8513
|
+
fitHeight?: number;
|
|
8514
|
+
/** Разворот вокруг вертикали, градусы (0 — модель смотрит на север). */
|
|
8515
|
+
rotation?: number;
|
|
8516
|
+
/**
|
|
8517
|
+
* Доборные наклоны в градусах — вокруг осей X и Z ПРОСТРАНСТВА МОДЕЛИ.
|
|
8518
|
+
*
|
|
8519
|
+
* Нужны размещениям из редактора: там у объекта три угла, и хотя в наших
|
|
8520
|
+
* данных сейчас ненулевой только разворот, поворот лежащего набок объекта
|
|
8521
|
+
* задаётся именно ими.
|
|
8522
|
+
*/
|
|
8523
|
+
rotationTiltX?: number;
|
|
8524
|
+
rotationTiltZ?: number;
|
|
8525
|
+
/**
|
|
8526
|
+
* Появляться ростом из земли, как здания.
|
|
8527
|
+
*
|
|
8528
|
+
* По умолчанию ВЫКЛЮЧЕНО: модель, добавленную приложением через `addModel`,
|
|
8529
|
+
* оно ожидает увидеть на своём месте сразу. Включают его детальные
|
|
8530
|
+
* 3D-объекты карты — там объект подъезжает сам, и рост объясняет, откуда он.
|
|
8531
|
+
*/
|
|
8532
|
+
growIn?: boolean;
|
|
8533
|
+
visible?: boolean;
|
|
8534
|
+
userData?: Record<string, unknown>;
|
|
8535
|
+
id?: string;
|
|
8536
|
+
}
|
|
8537
|
+
declare class Model {
|
|
8538
|
+
readonly id: string;
|
|
8539
|
+
visible: boolean;
|
|
8540
|
+
userData: Record<string, unknown>;
|
|
8541
|
+
coordinates: LngLatLike;
|
|
8542
|
+
altitude: number;
|
|
8543
|
+
/**
|
|
8544
|
+
* ПОДЪЁМ РЕЛЬЕФОМ, метры: высота земли под моделью.
|
|
8545
|
+
*
|
|
8546
|
+
* Держится отдельно от `altitude`, а не складывается с ней при создании, по двум причинам: сама
|
|
8547
|
+
* высота модели приходит из данных и не должна теряться, а рельеф догружается сетью и меняется
|
|
8548
|
+
* уже после того, как модель поставлена.
|
|
8549
|
+
*/
|
|
8550
|
+
groundZ: number;
|
|
8551
|
+
rotation: number;
|
|
8552
|
+
rotationTiltX: number;
|
|
8553
|
+
rotationTiltZ: number;
|
|
8554
|
+
scale: number;
|
|
8555
|
+
fitHeight?: number;
|
|
8556
|
+
/** Разобранная геометрия; null, пока грузится. */
|
|
8557
|
+
mesh: ModelMesh | null;
|
|
8558
|
+
/** Готовые картинки базового цвета — по индексу из `mesh.images`. */
|
|
8559
|
+
bitmaps: (ImageBitmap | null)[];
|
|
8560
|
+
error: string | null;
|
|
8561
|
+
private loading;
|
|
8562
|
+
/**
|
|
8563
|
+
* Адрес меша — он же ключ ОБЩИХ ресурсов GPU.
|
|
8564
|
+
*
|
|
8565
|
+
* У замены по типу сотни копий одного файла (на замере 634 правила из 653 размещений), и меш у
|
|
8566
|
+
* них буквально один объект: кеш ассетов отдаёт его по этому же адресу. Значит и буферы с
|
|
8567
|
+
* текстурами обязаны быть общими, иначе каждая копия везёт в память свою.
|
|
8568
|
+
*/
|
|
8569
|
+
readonly url: string;
|
|
8570
|
+
private readonly fetchBytes?;
|
|
8571
|
+
private matrix;
|
|
8572
|
+
/**
|
|
8573
|
+
* Появление: доля роста по вертикали, 0..1.
|
|
8574
|
+
*
|
|
8575
|
+
* Ровно то же, что у зданий (`u_height_scale`): объект вырастает из земли, а
|
|
8576
|
+
* не возникает целиком. Для модели это не отдельный проход, а множитель к
|
|
8577
|
+
* вертикальной оси базиса — та же матрица уходит и в карту теней, поэтому
|
|
8578
|
+
* тень растёт вместе с объектом.
|
|
8579
|
+
*/
|
|
8580
|
+
grow: number;
|
|
8581
|
+
/** Куда идёт появление: 1 — вырастает, 0 — уходит в землю. */
|
|
8582
|
+
growTarget: 0 | 1;
|
|
8583
|
+
private animateIn;
|
|
8584
|
+
private shrinkFrom;
|
|
8585
|
+
private growStart;
|
|
8586
|
+
/**
|
|
8587
|
+
* Прозрачность, 0..1 — ею объект уступает место плану этажа и возвращается.
|
|
8588
|
+
*
|
|
8589
|
+
* Отдельно от `grow`, хотя оба про «появился/пропал». Рост — это ПОЯВЛЕНИЕ
|
|
8590
|
+
* объекта на карте (он вырастает из земли, как здание), и он уместен, когда
|
|
8591
|
+
* объект действительно приехал или уехал. А здесь объект никуда не девается:
|
|
8592
|
+
* камера просто зашла внутрь дома, и модель обязана уйти, не привлекая к
|
|
8593
|
+
* себе внимания, — вырастающая обратно из земли башня при выходе из плана
|
|
8594
|
+
* читается как новое событие на карте, которого не было.
|
|
8595
|
+
*/
|
|
8596
|
+
fade: number;
|
|
8597
|
+
/**
|
|
8598
|
+
* Непрозрачность из СТИЛЯ (`osmgl-model-opacity` слоя моделей), 0..1. Множится на `fade`: стиль
|
|
8599
|
+
* задаёт облик, а `fade` — уступку плану этажа, и одно не должно перетирать другое.
|
|
8600
|
+
*/
|
|
8601
|
+
styleOpacity: number;
|
|
8602
|
+
/** Отбрасывает ли модель тень (`osmgl-model-cast-shadows`). Получает её в любом случае. */
|
|
8603
|
+
castShadows: boolean;
|
|
8604
|
+
/**
|
|
8605
|
+
* ПОВЕРХ СЦЕНЫ — значок, а не предмет города (машина навигатора, `NavCarOverlay`).
|
|
8606
|
+
*
|
|
8607
|
+
* Такая модель не рисуется в проходе объёма: слой отдаёт её отдельному проходу в самом конце
|
|
8608
|
+
* кадра (`renderOnTop`), после подписей и с ОЧИЩЕННОЙ глубиной. Дом впереди её не закрывает, а
|
|
8609
|
+
* свои грани она по-прежнему прячет друг за другом. Так ведёт себя курсор Google: машина
|
|
8610
|
+
* крупнее настоящей (держит размер значка), и в честной глубине она бы втыкалась в дома на
|
|
8611
|
+
* каждом повороте. В карту теней и в пачку (`renderInstanced`) такие модели не идут.
|
|
8612
|
+
*/
|
|
8613
|
+
onTop: boolean;
|
|
8614
|
+
/** Итоговая непрозрачность в кадре. */
|
|
8615
|
+
get alpha(): number;
|
|
8616
|
+
private fadeTarget;
|
|
8617
|
+
private fadeFrom;
|
|
8618
|
+
private fadeStart;
|
|
8619
|
+
private matrix32;
|
|
8620
|
+
private nodeMatrix32;
|
|
8621
|
+
private normal32;
|
|
8622
|
+
constructor(options: ModelOptions);
|
|
8623
|
+
get isLoaded(): boolean;
|
|
8624
|
+
/** Скачивает и разбирает модель. Повторные вызовы возвращают ту же работу. */
|
|
8625
|
+
load(onDone?: () => void): Promise<void>;
|
|
8626
|
+
/**
|
|
8627
|
+
* Продвинуть появление. Возвращает true, пока рост не закончен, — это сигнал
|
|
8628
|
+
* карте просить следующий кадр.
|
|
8629
|
+
*
|
|
8630
|
+
* Отсчёт начинается с ПЕРВОГО кадра, где модель готова: до этого её ещё нет
|
|
8631
|
+
* на экране, и стартуй мы от начала загрузки, объект просто возникал бы уже
|
|
8632
|
+
* выросшим.
|
|
8633
|
+
*/
|
|
8634
|
+
advanceGrow(durationSec: number): boolean;
|
|
8635
|
+
/**
|
|
8636
|
+
* Начать уход в землю. Повторный вызов ничего не сбрасывает — иначе объект
|
|
8637
|
+
* на границе радиуса дёргался бы, начиная исчезновение заново каждый кадр.
|
|
8638
|
+
*/
|
|
8639
|
+
retire(): void;
|
|
8640
|
+
/**
|
|
8641
|
+
* Спрятать или показать объект ПЛАВНО.
|
|
8642
|
+
*
|
|
8643
|
+
* Повторный вызов с той же целью ничего не сбрасывает: решение принимается
|
|
8644
|
+
* каждый кадр (план этажа то открыт, то нет), и перезапуск отсчёта оставил бы
|
|
8645
|
+
* прозрачность навсегда замершей у начального значения.
|
|
8646
|
+
*/
|
|
8647
|
+
setHidden(hidden: boolean): void;
|
|
8648
|
+
/**
|
|
8649
|
+
* Продвинуть исчезновение. Возвращает true, пока оно идёт, — карте это сигнал
|
|
8650
|
+
* просить следующий кадр.
|
|
8651
|
+
*/
|
|
8652
|
+
advanceFade(durationSec: number): boolean;
|
|
8653
|
+
/** Объект уже стоит: показать сразу, без повторного роста. */
|
|
8654
|
+
markGrown(): void;
|
|
8655
|
+
/** Вернуть к жизни объект, который уже начал уходить. */
|
|
8656
|
+
revive(): void;
|
|
8657
|
+
/** Эффективный масштаб с учётом `fitHeight`. */
|
|
8658
|
+
effectiveScale(): number;
|
|
8659
|
+
/**
|
|
8660
|
+
* Радиус охватывающей сферы в МЕТРАХ — для отсечения по пирамиде видимости.
|
|
8661
|
+
*
|
|
8662
|
+
* Берём габарит из glTF и умножаем на действующий масштаб. Сфера заведомо больше настоящей формы,
|
|
8663
|
+
* и это правильная сторона ошибки: лишний раз нарисовать дальнее дерево дешевле, чем срезать
|
|
8664
|
+
* половину дворца, попавшую в кадр краем.
|
|
8665
|
+
*/
|
|
8666
|
+
boundingRadiusM(): number;
|
|
8667
|
+
/** Начало координат модели в нормализованном меркаторе. */
|
|
8668
|
+
origin(): {
|
|
8669
|
+
x: number;
|
|
8670
|
+
y: number;
|
|
8671
|
+
};
|
|
8672
|
+
/**
|
|
8673
|
+
* Матрица «единицы модели → локальные координаты объекта».
|
|
8674
|
+
*
|
|
8675
|
+
* Смена системы координат здесь и есть всё содержание: в glTF оси
|
|
8676
|
+
* `x = вправо, y = вверх, z = на зрителя`, у нас — `x = восток, y = ЮГ,
|
|
8677
|
+
* z = вверх`. Отсюда перестановка `(x, y, z) → (x, z, y)`: она же меняет
|
|
8678
|
+
* рукость системы с правой на левую, а наша именно левая.
|
|
8679
|
+
*
|
|
8680
|
+
* Горизонталь переводится в нормализованный меркатор (делением на длину
|
|
8681
|
+
* параллели), вертикаль остаётся В МЕТРАХ: матрица камеры сама домножит её на
|
|
8682
|
+
* `pixelsPerMeter`. Перепутать эти две — классический способ получить модель,
|
|
8683
|
+
* которая с зумом растёт или тонет в земле.
|
|
8684
|
+
*/
|
|
8685
|
+
private localMatrix;
|
|
8686
|
+
/**
|
|
8687
|
+
* Матрица модели в ЗАДАННОМ пространстве объекта.
|
|
8688
|
+
*
|
|
8689
|
+
* Отдельный метод, потому что пространств два: камера и источник света. Обе
|
|
8690
|
+
* матрицы обязаны строиться из одной локальной — иначе глубина, записанная в
|
|
8691
|
+
* карту теней, разойдётся с той, по которой модель потом сравнивают, и модель
|
|
8692
|
+
* начнёт затенять сама себя.
|
|
8693
|
+
*/
|
|
8694
|
+
matrixInSpace(objectMatrix: Float32Array, out32?: Float32Array): Float32Array;
|
|
8695
|
+
/**
|
|
8696
|
+
* Позиция камеры В ЕДИНИЦАХ МОДЕЛИ — для отражений.
|
|
8697
|
+
*
|
|
8698
|
+
* Отражению нужен вектор взгляда, а вершины и собственные светильники модели живут в её
|
|
8699
|
+
* собственном пространстве. Переводить их в мировые координаты пришлось бы на каждый экземпляр;
|
|
8700
|
+
* дешевле перевести туда одну камеру.
|
|
8701
|
+
*
|
|
8702
|
+
* Общей инверсии матрицы здесь нет и не нужно. `localMatrix` — это перестановка осей
|
|
8703
|
+
* (glTF x,y,z → восток, вверх, юг) с ОДНИМ масштабом плюс поворот, а такое обращается
|
|
8704
|
+
* транспонированием: сначала снимаем масштаб, потом поворот, потом перестановку.
|
|
8705
|
+
*
|
|
8706
|
+
* Тонкость с единицами: по горизонтали объектное пространство измеряется в долях меркатора, по
|
|
8707
|
+
* вертикали — в метрах. Поэтому горизонталь домножается на длину параллели, приводя всё к метрам,
|
|
8708
|
+
* и только затем делится на масштаб модели.
|
|
8709
|
+
*/
|
|
8710
|
+
cameraInModelSpace(tr: Transform): [number, number, number];
|
|
8711
|
+
/** Полная матрица модели для камеры. */
|
|
8712
|
+
matrixFor(tr: Transform): Float32Array;
|
|
8713
|
+
/**
|
|
8714
|
+
* Накрывает ли модель эту точку по горизонтали (нормализованный меркатор).
|
|
8715
|
+
*
|
|
8716
|
+
* Нужно маске заменённых зданий: модель дворца стоит не над одним домом, а
|
|
8717
|
+
* над целым комплексом, и «спрятать дом под точкой привязки» оставляет на
|
|
8718
|
+
* карте все его крылья. Пятно берём как ПОВЁРНУТЫЙ прямоугольник габарита:
|
|
8719
|
+
* настоящий контур модели нам взять неоткуда, а прямоугольник её габарита
|
|
8720
|
+
* ошибается наружу лишь на углах.
|
|
8721
|
+
*/
|
|
8722
|
+
coversPoint(mercX: number, mercY: number): boolean;
|
|
8723
|
+
/** Есть ли у модели клип — по нему карта решает, просить ли следующий кадр. */
|
|
8724
|
+
get isAnimated(): boolean;
|
|
8725
|
+
/**
|
|
8726
|
+
* Матрица ПОДВИЖНОГО узла для камеры: та же модельная, домноженная справа на
|
|
8727
|
+
* положение узла в этот момент.
|
|
8728
|
+
*
|
|
8729
|
+
* Отдельный метод, а не поле: узлов у клипа единицы, а считается это на
|
|
8730
|
+
* каждый кадр и на каждую модель — держать кэш дороже, чем перемножить.
|
|
8731
|
+
*/
|
|
8732
|
+
matrixForNode(tr: Transform, node: number, timeSec: number): Float32Array;
|
|
8733
|
+
/**
|
|
8734
|
+
* Матрица подвижного узла в ЗАДАННОМ пространстве объекта.
|
|
8735
|
+
*
|
|
8736
|
+
* Пространств два — камера и источник света, — и обе матрицы обязаны
|
|
8737
|
+
* строиться из одной и той же позы узла: разойдись они, и анимированная
|
|
8738
|
+
* часть начнёт отбрасывать тень от другого своего положения.
|
|
8739
|
+
*/
|
|
8740
|
+
matrixInSpaceForNode(objectMatrix: Float32Array, node: number, timeSec: number, out32: Float32Array): Float32Array;
|
|
8741
|
+
/**
|
|
8742
|
+
* Матрица нормалей: те же оси, но без масштаба и без переноса.
|
|
8743
|
+
* Масштаб у нас неравномерный (горизонталь в меркаторе, вертикаль в метрах),
|
|
8744
|
+
* поэтому нормали нельзя гонять основной матрицей — они перестанут быть
|
|
8745
|
+
* перпендикулярными, и свет поедет.
|
|
8746
|
+
*/
|
|
8747
|
+
normalMatrix(): Float32Array;
|
|
8748
|
+
}
|
|
8749
|
+
|
|
5137
8750
|
/**
|
|
5138
8751
|
* Слой 3D-моделей.
|
|
5139
8752
|
*
|
|
@@ -13069,4 +16682,4 @@ declare class Map$1 extends Evented<MapEvents> {
|
|
|
13069
16682
|
destroy(): void;
|
|
13070
16683
|
}
|
|
13071
16684
|
|
|
13072
|
-
export { type AnimationOptions, type ArrowSize, AssetLoader, type AssetLoaderOptions, AttributionControl, type AxisChain, BASE_ICONS, BASE_SOURCE, BUILDING_HEIGHT_SCALE, BUILDING_POS_SCALE, BUILDING_VERTEX_STRIDE, BackgroundLayerSpec, BoxZoomHandler, type BridgeProfile, type BuildingCell, type BuildingCells, type BuildingHit, type BuildingsMesh, CELL_GRID, CIRCLE_PROPS, CIRCLE_VERTEX_STRIDE, CITY_STYLE, CLIP_END, CLIP_START, type CameraOptions, type CameraUpdate, type CircleOptions as CircleBucketOptions, type CircleMesh, type CollatorValue, ColorReliefLayerSpec, type ControlPosition, CooperativeGesturesHandler, type CoverOptions, type CustomLayer, DASH_MAX, DATA_PAINT_EXT_STRIDE, DATA_PAINT_STRIDE, DEFAULT_HEATMAP_COLOR, DEFAULT_ICONS, DEFAULT_SHADOWS, DEFAULT_STYLE, type DataPaintSpec, type DemCustomEncoding, type DemEncoding, DemLayerData, DemLayerSpec, DemLayers, DemSource, type DemSourceOptions, DemTile, DemTileEntry, DepthTarget, type DeviceHints, EXPRESSION_OPERATORS, type ExprContext, type ExprValue, type ExpressionIssue, type ExpressionOperatorRef, FACADE_FOCUS_RANGE_M, FACADE_GONE_MPP, FILL_VERTEX_STRIDE, FLIP_HOLD_DEG, FOG_FAR_MIN_M, FOG_NEAR_MIN_M, type FacadeView, FeaturePaint, type FeatureStateId, FeatureStatePainter, FeatureStateStore, Filter, type FitBoundsOptions, type FogPlanes, FogSpec, type FogWall, type FontFaceDeclaration, FontFaces, type FontFacesSpec, type FormatPiece, type FormatSectionData, type FormattedSection, type FormattedValue, FullscreenControl, GLOBAL_STATE, GLYPH_BORDER, GLYPH_SIZE, GRADIENT_SIZE, GRADIENT_STEP_SIZE, GROUND_SCALE, type GeoJSONData, type GeoJSONFeature, type GeoJSONFeatureCollection, type GeoJSONGeometry, type GeoJSONPosition, GeoJSONSource, GeolocateControl, GeomType, GestureHandler, type GestureOptions, GlobeControl, type Glyph, type GlyphMetric, GlyphSource, type GpuClass, GroundArrows, HEATMAP_LAYOUT, HEATMAP_PROPS, HEATMAP_VERTEX_STRIDE, HOST_SOURCE_KEY, type HeatmapMesh, type HeatmapOptions, HeatmapPass, HillshadeLayerSpec, ICON_ALIASES, ICON_SOURCES, type IControl, IconSource, ImageManager, type ImageValue, IndoorMask, Interpolated, type Junctions, LABEL_FOG_MAX, LD_DEFAULTS, LEVEL_LIMIT, LINE_PROGRESS_STRIDE, LINE_VERTEX_STRIDE, type LaneArrow, type LaneGuide, type LaneGuideOptions, LayerOpacityTarget, type LayerPlan, LayerRenderer, type LayerTypeName, type LayerTypeRef, type LdMesh, type LdMeshOptions, type LiftField, LightSpec, type LineGradientMesh, type LinePlacement, LngLat, LngLatBounds, LngLatBoundsLike, LngLatLike, type LoadStyleOptions, type LoadedStyle, LogoControl, MAPLIBRE_STYLES, MAPLIBRE_STYLE_BASE, MAPLIBRE_SUPPORT, MAPLIBRE_TRANSITION, MAX_GRADE, MESH_BOTTOM, MESH_ISLAND, MESH_KERB_SIDE, MESH_KERB_TOP, MESH_SIDE, MESH_TOP, MIN_PIER_HEIGHT_METERS, MITER_MAX_TURN, MLIGHT_CITY_STYLE, ML_EXTENT, MNIGHT_CITY_STYLE, Map$1 as Map, type MapCameraEvent, type MapEvents, type MapLayerEvent, type MapLayerEventType, type MapLibreImport, type MapLibreLayer, MapLibreLightSpec, type MapLibreSource, type MapLibreStyle, type MapLibreSupport, type MapLibreSupportStatus, MapObject, type MapOptions, Marker, type MarkerAnchor, type MarkerEvents, type MarkerOptions, type Marking, type MarkingKind, type MarkingOptions, type MarkingRing, type MediaCoordinates, type MediaKind, MediaSource, type MeteredPiece, MltTile, Model, ModelLayer, ModelMesh, NavigationControl, OCCLUSION_MAX_SAMPLES, OCCLUSION_NEAR_M, OCCLUSION_NEAR_SHARE, OCCLUSION_STEP_M, OCCLUSION_TOLERANCE_M, OSMGL_STYLES, ObjectManager, Objects3DLayout, Objects3DManager, type OverzoomPlan, PAINT_TRANSITIONS, PIER_SPACING_METERS, type Padding, PaintStamp, PaintTransitions, type Pier, type PierOptions, type PlacedGlyph, type PlacedSymbol, PointLike, type PolygonPiece, Popup, type PopupOptions, Projection, type PropRef, type PropType, type ProtocolHandler, type QualityChange, QualityGovernor, type QualityName, type QualityProfile, type QueriedFeature, type QueryGeometry, RELIEF_DARK_KEEP, RELIEF_DARK_LUMA, RELIEF_LIGHT_ALTITUDE, RELIEF_LIGHT_AZIMUTH, RELIEF_STYLE, ROAD_MESH_RADIUS_BY_CORNER, ROAD_SIGNS, type RampOptions, RasterSource, type RasterSourceOptions, RasterTile, type RenderedQueryOptions, type RoadAxis, type RoadChain, type RoadEdges, type RoadGraph, type RoadGraphOptions, type RoadHeightOptions, type RoadHeights, type RoadMesh, type RoadMeshOptions, type RoadNode, type RoadRay, type RoadSourceEdges, type RoadSurface, type RoadSurfaceOptions, type RoundOptions, SDF_EDGE, SDF_PX, SIGN_SIZE, SOFT_STYLE, SPLIT_SEP, STYLE_REFERENCE, STYLE_REFERENCE_EXPRESSIONS, STYLE_REFERENCE_EXPRESSION_GROUPS, STYLE_REFERENCE_V2_FLAGS, SURFACE_CUT_BLEED, SURFACE_LEVEL_SCALE, SURFACE_VERTEX_STRIDE, SYMBOL_DATA_FIELDS, ScaleControl, ScreenPoint$1 as ScreenPoint, SdfAtlas, type ShadowSettings, type ShapedImage, SkySpec, type SlitResult, SourceSpec, type StateIndex, StateIndexBuilder, Style, type StyleImage, type StyleImageData, type StyleImageOptions, type StyleIssue, type StyleLayerHit, StyleLayerSpec, type StyleReference, StyleSpec, StyleSpecV2, type StyleValidation, SymbolDataBuilder, type SymbolDataColumn, type SymbolDataColumns, type SymbolDataKind, type SymbolHit, SymbolRenderer, TAPER_METERS, TERRAIN_STYLE, THEMES, type TaperedWidth, TerrainControl, type ThemeInput, type ThemeSpec, ThemeSpecV2, type TileAddress, type TileEncoding, TileID, Transform, type TransformConstrain, type TransformRequest, TransitionSpec, VectorTileLayer, type ZoomCurve, abbreviateStreet, addGround, allowsVerticalWritingMode, anonymousParts, applyTheme, arrowLabelOffset, arrowVertices, asFormatted, asImage, bridgePiers, bridgeProfile, buildCells, buildRoadGraph, buildTile, buildZoomFor, builtinMapLibreStyle, builtinOsmglStyle, cellBeyondFocus, cellFacadeGone, cellGround, cellOutside, chainAxes, changedBuckets, circleValuesOf, clampPixelRatio, classifyRenderer, clipLineToRect, clipLineWithMetrics, clipPolygonParts, closeSlits, clusterProperties, colorsOf, contrastFactor, convertFilter as convertMapLibreFilter, convertValue as convertMapLibreValue, coordinateDigits, coveringTiles, createGround, cutMargin, dashArrayAt, dashRow, dataPaintT, Map$1 as default, densifyLine, deviceHints, easeCubicInOut, evaluateColor, evaluateExpression, evaluateNumber, evaluateVec2, expressionColor, expressionIssues, expressionNumber, extractFeature, facadeFocusBand, facadeGoneDepth, facadeLite, facadeView, featureContext, featureDrivenPaint, featureLevel, featureRuns, featureStateIdOf, fillFootprint, fillTileUrl, fitIconToText, fogCutoffOf, fogPlanes, fogRangeOf, fogWall, footprintOf, formatHash, formattedSections, generateBuildings, generateCircles, generateFill, generateGradientLine, generateHeatmap, generateLine, generateSurface, generateSymbols, groundAt, heatmapRamp, heatmapT, iconRotateOf, iconRotation, importMapLibreStyle, insideFootprint, isExpression, isMapLibreStyle, isStepGradient, isSupportedScript, junctionIndex, keptIndices, labelFogFade, labelReach, laneArrow, laneGuides, latRange, layerOpacityOf, layerZoomCeiling, layersToRebuild, layoutAtZoom, ldRoadMesh, liftFields, lineClipsOf, lineGradientRamp, loadMapLibreStyle, loadStyle, makeFeaturePaint, centerAnchor as mapLibreCenterAnchor, clipLine as mapLibreClipLine, mapLibreFogDepth, mapLibreFogOpacity, mapLibreHorizon, lineAnchors as mapLibreLineAnchors, mapLibreSpot, matchesFilter, meanWidth, mercFeaturesToGeometry, mercatorBounds, mergeBuild, modelLodFloor, needsAdjust, needsDataPaint, nextQualityDown, numbersOf, overzoomPlan, packDem, parseGlbOffThread, parseGlyphs, parseHash, parseLift, parseUnicodeRange, parseVectorTile, patchUV, patternNameAt, patternOrigin, pickBuilding, pickFill, pitchIntent, pixelAlignShift, placeAlongLine, placeMarking, polylineLength, primaryVectorSource, projectLine as projectSymbolLine, promoteName, qualityFor, qualityProfile, queryRendered, querySource, refineLine, relaxAngle, relaxCurvature, relaxForMiter, reliefLight, reliefStops, reliefTintOn, replaceGlobalState, resolveStyleUrls, resolveSymbolColor, resolveSymbolField, resolveSymbolItem, resolveSymbolNumber, resolveSymbolVec2, resolveTemplate, rewriteSymbolPaint, ribbonFromEdges, ribbonRing, ribbonShape, ringEdges, roadEdges, roadHeights, roadMarkings, roadMesh, roadSurfaces, roundLine, roundRing, roundRings, saturationFactor, sdfFromAlpha, shapeFormatted, shapeText, shapeTextCached, shapeVertical, snapCutsInward, snapRoadEnds, speedSign, spinWeights, splitBucketKey, splitByGround, squareClosed, stitchPieces, stopLine, stretchQuads, styleWithTheme, surfaceWritesDepth, symbolDataPlan, taperedWidth, terrainOccludes, tileInBounds, tileLayer, tileRingsToGeometry, tileUrl, toMercator, transitionOf, translateTileUnits, translatedMatrix, tryParseColor, unpackVector, usesFeatureState, validateStyle, validateTheme, variableOffset, verticalizePunctuation, waffle, wantsHostSource, withHostSource, worldAlongLine, writeCircleValues, yieldTargetsOf, zebra, zoomCeilingOf, zoomCurveOf };
|
|
16685
|
+
export { type AlongFade, type AnimationOptions, type ArrowSize, AssetLoader, type AssetLoaderOptions, AttributionControl, type AxisChain, BASE_ICONS, BASE_SOURCE, BUILDING_HEIGHT_SCALE, BUILDING_POS_SCALE, BUILDING_VERTEX_STRIDE, type BackgroundLayerSpec, BoxZoomHandler, type BridgeProfile, type BuildingCell, type BuildingCells, type BuildingHit, type BuildingsMesh, CELL_GRID, CIRCLE_PROPS, CIRCLE_VERTEX_STRIDE, CITY_STYLE, CLIP_END, CLIP_START, type CameraOptions, type CameraUpdate, Circle, type CircleOptions as CircleBucketOptions, type CircleLayerSpec, type CircleMesh, type CircleOptions$1 as CircleOptions, type CollatorValue, type ColorReliefLayerSpec, type ControlPosition, CooperativeGesturesHandler, type CoverOptions, type CustomLayer, DASH_MAX, DATA_PAINT_EXT_STRIDE, DATA_PAINT_STRIDE, DEFAULT_FOG, DEFAULT_HEATMAP_COLOR, DEFAULT_ICONS, DEFAULT_LIGHT, DEFAULT_MAPLIBRE_LIGHT, DEFAULT_SHADOWS, DEFAULT_SKY, DEFAULT_STYLE, type DataPaintSpec, type DemCustomEncoding, type DemEncoding, DemLayerData, type DemLayerSpec, DemLayers, DemSource, type DemSourceOptions, DemTile, DemTileEntry, DepthTarget, type DeviceHints, EARTH_CIRCUMFERENCE, EXPRESSION_OPERATORS, type ExprContext, type ExprValue, type ExpressionIssue, type ExpressionOperatorRef, FACADE_FOCUS_RANGE_M, FACADE_GONE_MPP, FILL_VERTEX_STRIDE, FLIP_HOLD_DEG, FOG_CUTOFF_MIN_M, FOG_FAR_MIN_M, FOG_NEAR_MIN_M, type FacadeView, FeaturePaint, type FeatureStateId, FeatureStatePainter, FeatureStateStore, type Filter, type FitBoundsOptions, type FitViewport, type FogPlanes, type FogSpec, type FogWall, type FontFaceDeclaration, FontFaces, type FontFacesSpec, type FormatPiece, type FormatSectionData, type FormattedSection, type FormattedValue, FullscreenControl, GLOBAL_STATE, GLOBE_MAX_PITCH, GLOBE_ZOOM_MAX, GLOBE_ZOOM_MIN, GLYPH_BORDER, GLYPH_SIZE, GRADIENT_SIZE, GRADIENT_STEP_SIZE, GROUND_SCALE, type GeoJSONData, type GeoJSONFeature, type GeoJSONFeatureCollection, type GeoJSONGeometry, type GeoJSONPosition, GeoJSONSource, GeolocateControl, GeomType, GestureHandler, type GestureOptions, GlobeControl, type Glyph, type GlyphMetric, GlyphSource, type GpuClass, GroundArrows, HEATMAP_LAYOUT, HEATMAP_PROPS, HEATMAP_VERTEX_STRIDE, HOST_SOURCE_KEY, type HeatmapLayerSpec, type HeatmapMesh, type HeatmapOptions, HeatmapPass, type HillshadeLayerSpec, ICON_ALIASES, ICON_SOURCES, type IControl, IconSource, ImageManager, type ImageValue, IndoorMask, type Interpolated, type Junctions, LABEL_FOG_MAX, LD_DEFAULTS, LEVEL_LIMIT, LINE_PROGRESS_STRIDE, LINE_VERTEX_STRIDE, type LaneArrow, type LaneGuide, type LaneGuideOptions, LayerOpacityTarget, type LayerPlan, LayerRenderer, type LayerSpecV2, type LayerTypeName, type LayerTypeRef, type LdMesh, type LdMeshOptions, type LiftAt, type LiftField, type LightSpec, type LineGradientMesh, type LinePlacement, type LngLat, LngLatBounds, type LngLatBoundsLike, type LngLatLike, type LoadStyleOptions, type LoadedStyle, LogoControl, MAPLIBRE_STYLES, MAPLIBRE_STYLE_BASE, MAPLIBRE_SUPPORT, MAPLIBRE_TRANSITION, MAX_GRADE, MAX_LATITUDE, MESH_BOTTOM, MESH_ISLAND, MESH_KERB_SIDE, MESH_KERB_TOP, MESH_SIDE, MESH_TOP, MIN_PIER_HEIGHT_METERS, MITER_MAX_TURN, MLIGHT_CITY_STYLE, ML_EXTENT, MNIGHT_CITY_STYLE, MODEL_VERTEX_STRIDE, Map$1 as Map, type MapCameraEvent, type MapEvents, type MapLayerEvent, type MapLayerEventType, type MapLibreImport, type MapLibreLayer, type MapLibreLightSpec, type MapLibreSource, type MapLibreStyle, type MapLibreSupport, type MapLibreSupportStatus, MapObject, type MapObjectOptions, type MapOptions, Marker, type MarkerAnchor, type MarkerEvents, type MarkerOptions, type Marking, type MarkingKind, type MarkingOptions, type MarkingRing, type MediaCoordinates, type MediaKind, MediaSource, type MeteredPiece, MltTile, Model, ModelLayer, type ModelLayerSpec, type ModelLayout, type ModelMesh, type ModelOptions, type ModelPrimitive, NavigationControl, OCCLUSION_MAX_SAMPLES, OCCLUSION_NEAR_M, OCCLUSION_NEAR_SHARE, OCCLUSION_STEP_M, OCCLUSION_TOLERANCE_M, OSMGL_FORMAT_VERSION, OSMGL_STYLES, OSMGL_VERSION_KEY, ObjectManager, type ObjectPaint, type ObjectPart, type Objects3DLayout, Objects3DManager, type OverzoomPlan, PAINT_TRANSITIONS, PIER_SPACING_METERS, PITCH_BY_ZOOM, type Padding, PaintStamp, PaintTransitions, type Pier, type PierOptions, type PlacedGlyph, type PlacedSymbol, type PointLike, Polygon, type PolygonOptions, type PolygonPiece, Polyline, type PolylineOptions, type PolylineSegment, Popup, type PopupOptions, type Projection, type PropRef, type PropType, type ProtocolHandler, type QualityChange, QualityGovernor, type QualityName, type QualityProfile, type QueriedFeature, type QueryGeometry, RELIEF_DARK_KEEP, RELIEF_DARK_LUMA, RELIEF_LIGHT_ALTITUDE, RELIEF_LIGHT_AZIMUTH, RELIEF_STYLE, ROAD_MESH_RADIUS_BY_CORNER, ROAD_SIGNS, RUNTIME_FILL_STRIDE, RUNTIME_LINE_STRIDE, type RampOptions, RasterSource, type RasterSourceOptions, RasterTile, type RenderedQueryOptions, type RoadAxis, type RoadChain, type RoadEdges, type RoadGraph, type RoadGraphOptions, type RoadHeightOptions, type RoadHeights, type RoadMesh, type RoadMeshOptions, type RoadNode, type RoadRay, type RoadSourceEdges, type RoadSurface, type RoadSurfaceOptions, type RoundOptions, RouteArea, type RouteAreaOptions, type RuntimeMesh, SDF_EDGE, SDF_PX, SIGN_SIZE, SOFT_STYLE, SPLIT_SEP, STYLE_REFERENCE, STYLE_REFERENCE_EXPRESSIONS, STYLE_REFERENCE_EXPRESSION_GROUPS, STYLE_REFERENCE_V2_FLAGS, SURFACE_CUT_BLEED, SURFACE_LEVEL_SCALE, SURFACE_VERTEX_STRIDE, SYMBOL_DATA_FIELDS, ScaleControl, type ScreenPoint$1 as ScreenPoint, SdfAtlas, type ShadowSettings, type ShapedImage, type SkySpec, type SlitResult, type SourceSpec, type StateIndex, StateIndexBuilder, Style, type StyleImage, type StyleImageData, type StyleImageOptions, type StyleIssue, type StyleLayerHit, type StyleLayerSpec, type StyleReference, type StyleSpec, type StyleSpecV2, type StyleValidation, SymbolDataBuilder, type SymbolDataColumn, type SymbolDataColumns, type SymbolDataKind, type SymbolHit, SymbolRenderer, TAPER_METERS, TERRAIN_STYLE, THEMES, TILE_SIZE, type TaperedWidth, TerrainControl, type ThemeInput, type ThemeSpec, type ThemeSpecV2, type TileAddress, type TileEncoding, TileID, Transform, type TransformConstrain, type TransformRequest, type TransitionSpec, VectorTile, VectorTileFeature, VectorTileLayer, type ZoomCurve, abbreviateStreet, addGround, allowsVerticalWritingMode, alongFadeFactor, altitudeFromMercatorZ, anonymousParts, applyTheme, arrowLabelOffset, arrowVertices, asFormatted, asImage, bridgePiers, bridgeProfile, buildCells, buildRoadGraph, buildRuntimeFill, buildRuntimeLine, buildTile, buildZoomFor, builtinMapLibreStyle, builtinOsmglStyle, cameraForBounds, cellBeyondFocus, cellFacadeGone, cellGround, cellOutside, chainAxes, changedBuckets, circleValuesOf, circumferenceAtLatitude, clampLat, clampPixelRatio, classifyRenderer, clipLineToRect, clipLineWithMetrics, clipPolygonParts, closeSlits, clusterProperties, colorsOf, contrastFactor, convertFilter as convertMapLibreFilter, convertValue as convertMapLibreValue, coordinateDigits, coveringTiles, createGround, cutMargin, dashArrayAt, dashRow, dataPaintT, Map$1 as default, densifyLine, deviceHints, distToSegment, easeCubicInOut, evaluateColor, evaluateExpression, evaluateNumber, evaluateVec2, expressionColor, expressionIssues, expressionNumber, extractFeature, facadeFocusBand, facadeGoneDepth, facadeLite, facadeView, featureContext, featureDrivenPaint, featureLevel, featureRuns, featureStateIdOf, fillFootprint, fillTileUrl, fitIconToText, fogCutoffOf, fogPlanes, fogRangeOf, fogWall, footprintOf, formatHash, formattedSections, generateBuildings, generateCircles, generateFill, generateGradientLine, generateHeatmap, generateLine, generateSurface, generateSymbols, globeBasis, globeFlatMix, globeRadius, globeToLocal, groundAt, heatmapRamp, heatmapT, iconRotateOf, iconRotation, importMapLibreStyle, insideFootprint, isDemLayer, isExpression, isMapLibreStyle, isOsmglV2, isStepGradient, isSupportedScript, junctionIndex, keptIndices, labelFogFade, labelReach, laneArrow, laneGuides, latFromMercatorY, latRange, layerOpacityOf, layerV1toV2, layerZoomCeiling, layersToRebuild, layoutAtZoom, ldRoadMesh, liftFields, lineClipsOf, lineGradientRamp, lngFromMercatorX, lngLatToUnit, loadMapLibreStyle, loadStyle, makeFeaturePaint, centerAnchor as mapLibreCenterAnchor, clipLine as mapLibreClipLine, mapLibreFogDepth, mapLibreFogOpacity, mapLibreHorizon, lineAnchors as mapLibreLineAnchors, mapLibreSpot, matchesFilter, meanWidth, mercFeaturesToGeometry, mercatorBounds, mercatorMetersPerTile, mercatorX, mercatorY, mercatorZFromAltitude, mergeBuild, metersPerPixel, metersPerTile, modelLodFloor, needsAdjust, needsDataPaint, nextQualityDown, numbersOf, overzoomPlan, packDem, parseGlb, parseGlbAsync, parseGlbOffThread, parseGlyphs, parseHash, parseLift, parseUnicodeRange, parseVectorTile, patchUV, patternNameAt, patternOrigin, pickBuilding, pickFill, pitchIntent, pitchLimitAt, pixelAlignShift, pixelsPerMeter, placeAlongLine, placeMarking, pointInRing, polylineLength, primaryVectorSource, projectLine as projectSymbolLine, promoteName, propertyV2toV1, qualityFor, qualityProfile, queryRendered, querySource, raySphere, refineLine, relaxAngle, relaxCurvature, relaxForMiter, reliefLight, reliefStops, reliefTintOn, replaceGlobalState, resolveStyleUrls, resolveSymbolColor, resolveSymbolField, resolveSymbolItem, resolveSymbolNumber, resolveSymbolVec2, resolveTemplate, rewriteSymbolPaint, ribbonFromEdges, ribbonRing, ribbonShape, ringEdges, roadEdges, roadHeights, roadMarkings, roadMesh, roadSurfaces, roundLine, roundRing, roundRings, saturationFactor, sdfFromAlpha, shapeFormatted, shapeText, shapeTextCached, shapeVertical, snapCutsInward, snapRoadEnds, speedSign, spinWeights, splitBucketKey, splitByGround, splitPolygons, squareClosed, stitchPieces, stopLine, stretchQuads, styleV1toV2, styleWithTheme, surfaceWritesDepth, symbolDataPlan, taperedWidth, terrainOccludes, themeToInternal, themeV1toV2, tileInBounds, tileLayer, tileOriginMeters, tileRingsToGeometry, tileUrl, toLngLat, toMapLibreStyle, toMercator, toPoint, transitionOf, translateTileUnits, translatedMatrix, tryParseColor, unitToLngLat, unpackVector, usesFeatureState, validateStyle, validateTheme, variableOffset, verticalizePunctuation, waffle, wantsHostSource, withHostSource, worldAlongLine, worldSize, writeCircleValues, yieldTargetsOf, zebra, zoomCeilingOf, zoomCurveOf };
|