osmgl 0.7.3 → 0.8.0

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/osmgl.d.cts CHANGED
@@ -697,6 +697,69 @@ declare class Shader {
697
697
  destroy(): void;
698
698
  }
699
699
 
700
+ /**
701
+ * Разбор Mapbox Vector Tile (spec 2.1) — наш тайлсервер отдаёт именно его
702
+ * (схема OpenMapTiles v3: building / transportation / water / landuse / poi …).
703
+ *
704
+ * Читаем «лениво»: сначала только оглавление слоёв, геометрию каждой фичи
705
+ * распаковываем по требованию. На тайл с 20 тыс. фич это разница между
706
+ * 40 мс и 3 мс, когда генератору нужен один слой из пятнадцати.
707
+ */
708
+ declare const enum GeomType {
709
+ Unknown = 0,
710
+ Point = 1,
711
+ LineString = 2,
712
+ Polygon = 3
713
+ }
714
+ type PropValue = string | number | boolean | null;
715
+ /** Кольцо/линия: плоский массив [x0,y0,x1,y1,...] в координатах тайла [0..extent]. */
716
+ type Ring = number[];
717
+ declare class VectorTileFeature {
718
+ private pbf;
719
+ readonly keys: string[];
720
+ readonly values: PropValue[];
721
+ readonly extent: number;
722
+ id?: number;
723
+ type: GeomType;
724
+ properties: Record<string, PropValue>;
725
+ /** Позиция блока геометрии в буфере; -1 — геометрии нет. Пишется читателем полей. */
726
+ geomOffset: number;
727
+ constructor(pbf: Pbf, keys: string[], values: PropValue[], extent: number);
728
+ static read(pbf: Pbf, end: number, keys: string[], values: PropValue[], extent: number): VectorTileFeature;
729
+ /** Кольца/линии фичи. Для полигонов внешние и внутренние идут вперемешку — см. splitPolygons. */
730
+ loadGeometry(): Ring[];
731
+ /** BBox фичи в координатах тайла — дешёвый отсев до триангуляции. */
732
+ bbox(): [number, number, number, number];
733
+ }
734
+ declare class VectorTileLayer {
735
+ private pbf;
736
+ version: number;
737
+ name: string;
738
+ extent: number;
739
+ readonly featureOffsets: number[];
740
+ readonly keys: string[];
741
+ readonly values: PropValue[];
742
+ constructor(pbf: Pbf);
743
+ static read(pbf: Pbf, end: number): VectorTileLayer;
744
+ get length(): number;
745
+ feature(i: number): VectorTileFeature;
746
+ /** Итератор по всем фичам слоя. */
747
+ features(): Generator<VectorTileFeature>;
748
+ }
749
+ declare class VectorTile {
750
+ readonly layers: Record<string, VectorTileLayer>;
751
+ constructor(buffer: ArrayBuffer | Uint8Array);
752
+ }
753
+ /**
754
+ * Разбивает кольца полигона на группы «внешнее + его дырки».
755
+ * Ориентация по знаку площади: в MVT внешние кольца по часовой (положительная
756
+ * площадь в системе с Y вниз), дырки — против.
757
+ */
758
+ declare function splitPolygons(rings: Ring[]): {
759
+ outer: Ring;
760
+ holes: Ring[];
761
+ }[];
762
+
700
763
  /**
701
764
  * Формат стиля движка.
702
765
  *
@@ -1442,6 +1505,100 @@ interface StyleSpec {
1442
1505
  */
1443
1506
  declare const DEFAULT_LIGHT: LightSpec;
1444
1507
 
1508
+ /**
1509
+ * Генератор геометрии зданий: экструзия полигонов слоя `building` (схема OpenMapTiles v3).
1510
+ * Работает в воркере, отдаёт готовые типизированные массивы — они уходят в главный
1511
+ * поток transfer'ом (без копирования) и грузятся в GPU как есть.
1512
+ *
1513
+ * Формат вершины (stride 18 байт):
1514
+ * a_pos 2 × Int16 off 0 координаты тайла [0..extent]
1515
+ * a_height 1 × Uint16 off 4 высота вершины в метрах × 4 (до 16383 м, шаг 0.25)
1516
+ * a_tint 1 × Uint8 off 6 оттенок здания (одинаков у всех его вершин)
1517
+ * a_ao 1 × Uint8 off 7 0 — основание, 255 — верх
1518
+ * a_normal 3 × Int8n off 8 нормаль
1519
+ * a_kind 1 × Uint8 off 11 тип поверхности и класс фасада
1520
+ * a_wall 3 × Uint16 off 12 фасад: смещение вдоль грани, её ширина и высота (метры × 4)
1521
+ *
1522
+ * Высота ушла из Float32 в Uint16 ради места под a_tint: без разброса оттенка
1523
+ * квартал выглядит одной сплошной массой.
1524
+ *
1525
+ * `a_wall` появился ради РОВНОЙ раскладки окон. Сначала координата вдоль стены
1526
+ * считалась в шейдере как проекция позиции на её направление — сетка тогда общая
1527
+ * на всю карту, и грань режет её где придётся: у угла дома получается половина
1528
+ * окна, а простенки у разных стен разной ширины. Ширина и высота грани позволяют
1529
+ * ВПИСАТЬ сетку в неё: поля по краям, целое число ячеек, окно целиком.
1530
+ */
1531
+ declare const BUILDING_VERTEX_STRIDE = 18;
1532
+ /** Множитель упаковки высоты в Uint16. */
1533
+ declare const BUILDING_HEIGHT_SCALE = 32;
1534
+ /**
1535
+ * Множитель упаковки ПОЛОЖЕНИЯ вершины: сколько единиц Int16 приходится на единицу тайла.
1536
+ *
1537
+ * Было единица — то есть 0.47 м на z14, потому что координаты в MVT целые и вершину писали как
1538
+ * есть. Пока углы дома были прямыми, этого хватало: вершина и так стояла в узле сетки. Со
1539
+ * СКРУГЛЕНИЕМ хватать перестало — дуга радиусом 1.6 м это семь точек в пределах трёх единиц тайла,
1540
+ * и округление сажает их на ту же сетку: вместо дуги выходит лесенка со ступенью в полметра, она же
1541
+ * «угловатость» на ближнем зуме.
1542
+ *
1543
+ * Восемь единиц на тайловую — это 5.9 см, и дуга снова читается дугой. Потолок: тайл 0..4096, при
1544
+ * ×8 это 0..32768, и последнее значение на единицу больше, чем помещается в Int16, — оно
1545
+ * прижимается (`clampI16`). Ошибка при этом 6 см и только у вершины, стоящей ровно на дальней
1546
+ * границе тайла.
1547
+ */
1548
+ declare const BUILDING_POS_SCALE = 8;
1549
+ interface BuildingsMesh {
1550
+ vertices: ArrayBuffer;
1551
+ indices: ArrayBuffer;
1552
+ /** Uint32Array: id фичи на каждый треугольник — для пикинга и подсветки. */
1553
+ featureIds: ArrayBuffer;
1554
+ vertexCount: number;
1555
+ indexCount: number;
1556
+ extent: number;
1557
+ }
1558
+ interface BuildingsOptions {
1559
+ /**
1560
+ * Радиус скругления углов в МЕТРАХ. Скругляется контур, а значит и стены, и
1561
+ * крыша — она строится по тому же кольцу. Ноль (по умолчанию) — острые углы,
1562
+ * как раньше.
1563
+ */
1564
+ cornerRadius?: number;
1565
+ /** Максимум отрезков на дугу: меньше — дешевле и угловатее. */
1566
+ cornerSegments?: number;
1567
+ /**
1568
+ * Сколько метров в одной единице тайла. Нужен, чтобы решать по РАЗМЕРУ: дом
1569
+ * в сотню квадратов получает скатную крышу, торговый центр — плоскую. Без
1570
+ * него один и тот же порог на разных зумах означал бы разные здания.
1571
+ */
1572
+ metersPerUnit?: number;
1573
+ }
1574
+ declare function generateBuildings(layer: VectorTileLayer, extent: number, filter?: Filter, options?: BuildingsOptions,
1575
+ /**
1576
+ * Куда складывать дома, задевающие границу тайла.
1577
+ *
1578
+ * Задан — такие дома здесь НЕ строятся: из куска правильной геометрии не выйдет, их соберут из
1579
+ * всех кусков сразу. Не задан — прежнее поведение, каждый кусок сам по себе.
1580
+ */
1581
+ seams?: BuildingSeam[]): BuildingsMesh | null;
1582
+ /**
1583
+ * Кусок дома, задевающего границу тайла: контур с пометкой ЛОЖНЫХ рёбер.
1584
+ *
1585
+ * Уезжает на главный поток, чтобы там сложиться с кусками соседних тайлов в целый дом.
1586
+ * Кольца — в координатах СВОЕГО тайла; общую систему строит уже сборщик, он знает номера тайлов.
1587
+ */
1588
+ interface BuildingSeam {
1589
+ osmId: number;
1590
+ height: number;
1591
+ minHeight: number;
1592
+ seed: number;
1593
+ tint: number;
1594
+ facade: number;
1595
+ outer: number[];
1596
+ holes: number[][];
1597
+ /** `cut[i]` — ребро от вершины i к i+1 порождено обрезкой, а не стеной дома. */
1598
+ outerCut: boolean[];
1599
+ holeCuts: boolean[][];
1600
+ }
1601
+
1445
1602
  /**
1446
1603
  * План для воркера и общие с ним имена.
1447
1604
  *
@@ -1523,69 +1680,6 @@ declare const BASE_SOURCE = "base";
1523
1680
  declare const SPLIT_SEP = "\u241F";
1524
1681
  declare const splitBucketKey: (layerId: string, value: string | number) => string;
1525
1682
 
1526
- /**
1527
- * Разбор Mapbox Vector Tile (spec 2.1) — наш тайлсервер отдаёт именно его
1528
- * (схема OpenMapTiles v3: building / transportation / water / landuse / poi …).
1529
- *
1530
- * Читаем «лениво»: сначала только оглавление слоёв, геометрию каждой фичи
1531
- * распаковываем по требованию. На тайл с 20 тыс. фич это разница между
1532
- * 40 мс и 3 мс, когда генератору нужен один слой из пятнадцати.
1533
- */
1534
- declare const enum GeomType {
1535
- Unknown = 0,
1536
- Point = 1,
1537
- LineString = 2,
1538
- Polygon = 3
1539
- }
1540
- type PropValue = string | number | boolean | null;
1541
- /** Кольцо/линия: плоский массив [x0,y0,x1,y1,...] в координатах тайла [0..extent]. */
1542
- type Ring = number[];
1543
- declare class VectorTileFeature {
1544
- private pbf;
1545
- readonly keys: string[];
1546
- readonly values: PropValue[];
1547
- readonly extent: number;
1548
- id?: number;
1549
- type: GeomType;
1550
- properties: Record<string, PropValue>;
1551
- /** Позиция блока геометрии в буфере; -1 — геометрии нет. Пишется читателем полей. */
1552
- geomOffset: number;
1553
- constructor(pbf: Pbf, keys: string[], values: PropValue[], extent: number);
1554
- static read(pbf: Pbf, end: number, keys: string[], values: PropValue[], extent: number): VectorTileFeature;
1555
- /** Кольца/линии фичи. Для полигонов внешние и внутренние идут вперемешку — см. splitPolygons. */
1556
- loadGeometry(): Ring[];
1557
- /** BBox фичи в координатах тайла — дешёвый отсев до триангуляции. */
1558
- bbox(): [number, number, number, number];
1559
- }
1560
- declare class VectorTileLayer {
1561
- private pbf;
1562
- version: number;
1563
- name: string;
1564
- extent: number;
1565
- readonly featureOffsets: number[];
1566
- readonly keys: string[];
1567
- readonly values: PropValue[];
1568
- constructor(pbf: Pbf);
1569
- static read(pbf: Pbf, end: number): VectorTileLayer;
1570
- get length(): number;
1571
- feature(i: number): VectorTileFeature;
1572
- /** Итератор по всем фичам слоя. */
1573
- features(): Generator<VectorTileFeature>;
1574
- }
1575
- declare class VectorTile {
1576
- readonly layers: Record<string, VectorTileLayer>;
1577
- constructor(buffer: ArrayBuffer | Uint8Array);
1578
- }
1579
- /**
1580
- * Разбивает кольца полигона на группы «внешнее + его дырки».
1581
- * Ориентация по знаку площади: в MVT внешние кольца по часовой (положительная
1582
- * площадь в системе с Y вниз), дырки — против.
1583
- */
1584
- declare function splitPolygons(rings: Ring[]): {
1585
- outer: Ring;
1586
- holes: Ring[];
1587
- }[];
1588
-
1589
1683
  /**
1590
1684
  * Сбор подписей из тайла.
1591
1685
  *
@@ -1683,13 +1777,17 @@ interface GeometryMesh {
1683
1777
  vertexCount: number;
1684
1778
  indexCount: number;
1685
1779
  extent: number;
1686
- /** Только для зданий: id фичи на треугольник (пикинг, подсветка). */
1780
+ /** id фичи на треугольник: пикинг, подсветка и вырезание заменённых моделью фич. */
1687
1781
  featureIds?: ArrayBuffer;
1688
1782
  /**
1689
1783
  * Только для поверхностей: сколько индексов в начале — обычная геометрия.
1690
1784
  * Хвост после них — крышки островов, их рисуют отдельно и только в глубину.
1691
1785
  */
1692
1786
  capIndexOffset?: number;
1787
+ /** Только для поверхностей: фичи каждой объединённой фигуры, `[сколько, id, …]`. */
1788
+ shapeFeatures?: ArrayBuffer;
1789
+ /** Только для поверхностей: где треугольники каждой фигуры, по четыре числа на фигуру. */
1790
+ shapeRanges?: ArrayBuffer;
1693
1791
  }
1694
1792
  /**
1695
1793
  * Подписи: геометрии нет, только точки привязки и строки. Раскладка глифов и
@@ -1737,6 +1835,13 @@ interface LoadedResponse {
1737
1835
  * У разбитых слоёв (`splitBy`) ключ составной — см. `splitBucketKey`.
1738
1836
  */
1739
1837
  buckets: Record<string, BucketMesh>;
1838
+ /**
1839
+ * Дома, задевающие границу тайла: контуры с пометкой ложных рёбер.
1840
+ *
1841
+ * В `buckets` их НЕТ — из куска правильной геометрии не построить. Главный поток складывает
1842
+ * куски соседних тайлов и собирает целый дом (см. `generators/stitch.ts`).
1843
+ */
1844
+ seams?: BuildingSeam[];
1740
1845
  /**
1741
1846
  * Какие значения разбиения встретились в этом тайле: имя свойства → значения.
1742
1847
  * По ним строится переключатель этажей — иначе клиенту неоткуда узнать, какие
@@ -2043,6 +2148,15 @@ declare class TileSource extends Evented<TileSourceEvents> {
2043
2148
  * куда пользователь заезжал за сеанс.
2044
2149
  */
2045
2150
  splitValues(property: string): (string | number)[];
2151
+ /**
2152
+ * Все ЗАГРУЖЕННЫЕ тайлы, а не только видимые.
2153
+ *
2154
+ * Нужно сборщику домов на границе (`layers/seams.ts`): дом собирается из кусков нескольких
2155
+ * тайлов, и стоит одному уехать из вида, как его кусок пропал бы из сборки — а на карте у
2156
+ * здания отвалилась бы половина. В кеше тайл живёт заметно дольше, чем в кадре, и этого хватает,
2157
+ * чтобы здание оставалось целым всю дорогу.
2158
+ */
2159
+ loadedTiles(): Iterable<[string, Tile]>;
2046
2160
  get pendingCount(): number;
2047
2161
  /** Пересчитывает видимый набор под текущую камеру и запускает недостающие загрузки. */
2048
2162
  update(tr: Transform): void;
@@ -3619,6 +3733,8 @@ declare class LayerRenderer {
3619
3733
  * перелёт через город.
3620
3734
  */
3621
3735
  private patternScale;
3736
+ /** Красить каждый тайл своим цветом — отладка стыков. См. `Map.setDebugTiles`. */
3737
+ debugTiles: boolean;
3622
3738
  /** Камера в метрах от мирового нуля — считается раз на кадр (см. render). */
3623
3739
  private cameraMeters;
3624
3740
  /** Пикселей буфера на пиксель вида — считается раз на кадр (см. render). */
@@ -3709,6 +3825,19 @@ declare class LayerRenderer {
3709
3825
  * подмешивать в неё чужой набор оказалось ненадёжно.
3710
3826
  */
3711
3827
  hiddenBuildings: ReadonlySet<number>;
3828
+ /** Сборщик домов, разрезанных границей тайла. См. `layers/seams.ts`. */
3829
+ private readonly seams;
3830
+ /** GPU-буферы сшитых домов по ключу тайла-хозяина. */
3831
+ private seamGpu;
3832
+ /**
3833
+ * Скрытые дома ПЛЮС собранные сборщиком — ПО ТАЙЛАМ.
3834
+ *
3835
+ * Именно по тайлам, а не одним списком на карту: замена собирается из тех кусков, что сейчас
3836
+ * загружены, и кусок, не вошедший в сборку, обязан рисоваться сам. Иначе часть здания, уехавшая
3837
+ * за край экрана вместе со своим тайлом, просто пропадала. Считается один раз на смену состава
3838
+ * (см. `syncHiddenStamp`), а не на каждый тайл каждого объёмного слоя.
3839
+ */
3840
+ private hiddenWithSeams;
3712
3841
  /**
3713
3842
  * То же для оболочек планов этажей (`indoor-venue`).
3714
3843
  *
@@ -3737,6 +3866,32 @@ declare class LayerRenderer {
3737
3866
  * каждый тайл каждого объёмного слоя, то есть десятки раз за кадр.
3738
3867
  */
3739
3868
  private syncHiddenStamp;
3869
+ /**
3870
+ * Поверхность без фигур, целиком заменённых 3D-моделями.
3871
+ *
3872
+ * Отдельно от `cutHidden`, потому что поверхность устроена иначе. Во-первых, треугольник тут
3873
+ * принадлежит ФИГУРЕ, а фигура — нескольким фичам сразу (соседние газоны сварены в один контур),
3874
+ * и убрать её можно, только если скрыты все до одной. Во-вторых, у поверхности два прохода:
3875
+ * крышки островов рисуются отдельно, хвостом буфера, и после резки их адреса сдвигаются.
3876
+ */
3877
+ private cutSurface;
3878
+ /**
3879
+ * Какие фичи ЕСТЬ в бакете. Живёт до перезагрузки тайла и переживает смену набора замен.
3880
+ *
3881
+ * Ограничен по размеру грубо, сбросом целиком: записи вытесненных тайлов сами по себе не уходят,
3882
+ * а точный учёт стоил бы больше, чем пересчёт пары сотен списков раз в долгую сессию.
3883
+ */
3884
+ private bucketIdCache;
3885
+ /** Разобранные поверхности без заменённых фигур. Сбрасывается вместе с `hiddenCut`. */
3886
+ private surfaceCut;
3887
+ private bucketIds;
3888
+ /**
3889
+ * Что заменено 3D-моделями. Для заливок и линий — единственный набор, который к ним применим.
3890
+ *
3891
+ * Швы сюда не идут: они про дома, разрезанные границей тайла, а дорожка режется по своей.
3892
+ * Пустой набор `cutHidden` пропускает даром, поэтому проверять его снаружи не нужно.
3893
+ */
3894
+ private replacedIds;
3740
3895
  /** Набор, которым режется слой: у домов свой, у оболочек планов свой. */
3741
3896
  private hiddenFor;
3742
3897
  /**
@@ -3929,6 +4084,13 @@ declare class LayerRenderer {
3929
4084
  * порядке его закрыла бы крыша.
3930
4085
  */
3931
4086
  private drawOverlay;
4087
+ /**
4088
+ * Цвет отладочной подкраски тайла: постоянный для одного адреса и разный у соседей.
4089
+ *
4090
+ * Соседи обязаны отличаться заметно, иначе смысл теряется, поэтому оттенок берём не хешем, а
4091
+ * прямо по чётности координат — шесть цветов по кругу, и любые два смежных тайла всегда разные.
4092
+ */
4093
+ private tileTint;
3932
4094
  private applyTileScale;
3933
4095
  private applyMaterial;
3934
4096
  private drawFill;
@@ -3993,6 +4155,18 @@ declare class LayerRenderer {
3993
4155
  */
3994
4156
  private drawSurface;
3995
4157
  private drawBuildings;
4158
+ /** Подсветить один сшитый дом: геометрия берётся из его же меша. */
4159
+ private drawSeamHighlight;
4160
+ /** Нарисовать сшитые дома. Каждый лежит в координатах своего тайла-хозяина. */
4161
+ private drawSeams;
4162
+ /**
4163
+ * Освободить буферы ТОЛЬКО тех хозяев, чья геометрия пересобрана.
4164
+ *
4165
+ * Раньше здесь сносился весь набор, и следующий кадр заливал на видеокарту все сшитые дома
4166
+ * заново — на каждый приехавший тайл. При панораме тайлы приезжают непрерывно, так что рывки
4167
+ * были непрерывными тоже.
4168
+ */
4169
+ private syncSeamGpu;
3996
4170
  /**
3997
4171
  * Доля высоты для анимации «вырастания». Считается ОДНА на бакет и берётся
3998
4172
  * и основным проходом, и проходом теней: иначе тень появится раньше здания
@@ -4620,74 +4794,6 @@ declare function placeAlongLine(line: ScreenPoint[], glyphs: GlyphMetric[], text
4620
4794
  */
4621
4795
  declare function clipLineToRect(line: ScreenPoint[], width: number, height: number, margin: number): ScreenPoint[][];
4622
4796
 
4623
- /**
4624
- * Генератор геометрии зданий: экструзия полигонов слоя `building` (схема OpenMapTiles v3).
4625
- * Работает в воркере, отдаёт готовые типизированные массивы — они уходят в главный
4626
- * поток transfer'ом (без копирования) и грузятся в GPU как есть.
4627
- *
4628
- * Формат вершины (stride 18 байт):
4629
- * a_pos 2 × Int16 off 0 координаты тайла [0..extent]
4630
- * a_height 1 × Uint16 off 4 высота вершины в метрах × 4 (до 16383 м, шаг 0.25)
4631
- * a_tint 1 × Uint8 off 6 оттенок здания (одинаков у всех его вершин)
4632
- * a_ao 1 × Uint8 off 7 0 — основание, 255 — верх
4633
- * a_normal 3 × Int8n off 8 нормаль
4634
- * a_kind 1 × Uint8 off 11 тип поверхности и класс фасада
4635
- * a_wall 3 × Uint16 off 12 фасад: смещение вдоль грани, её ширина и высота (метры × 4)
4636
- *
4637
- * Высота ушла из Float32 в Uint16 ради места под a_tint: без разброса оттенка
4638
- * квартал выглядит одной сплошной массой.
4639
- *
4640
- * `a_wall` появился ради РОВНОЙ раскладки окон. Сначала координата вдоль стены
4641
- * считалась в шейдере как проекция позиции на её направление — сетка тогда общая
4642
- * на всю карту, и грань режет её где придётся: у угла дома получается половина
4643
- * окна, а простенки у разных стен разной ширины. Ширина и высота грани позволяют
4644
- * ВПИСАТЬ сетку в неё: поля по краям, целое число ячеек, окно целиком.
4645
- */
4646
- declare const BUILDING_VERTEX_STRIDE = 18;
4647
- /** Множитель упаковки высоты в Uint16. */
4648
- declare const BUILDING_HEIGHT_SCALE = 32;
4649
- /**
4650
- * Множитель упаковки ПОЛОЖЕНИЯ вершины: сколько единиц Int16 приходится на единицу тайла.
4651
- *
4652
- * Было единица — то есть 0.47 м на z14, потому что координаты в MVT целые и вершину писали как
4653
- * есть. Пока углы дома были прямыми, этого хватало: вершина и так стояла в узле сетки. Со
4654
- * СКРУГЛЕНИЕМ хватать перестало — дуга радиусом 1.6 м это семь точек в пределах трёх единиц тайла,
4655
- * и округление сажает их на ту же сетку: вместо дуги выходит лесенка со ступенью в полметра, она же
4656
- * «угловатость» на ближнем зуме.
4657
- *
4658
- * Восемь единиц на тайловую — это 5.9 см, и дуга снова читается дугой. Потолок: тайл 0..4096, при
4659
- * ×8 это 0..32768, и последнее значение на единицу больше, чем помещается в Int16, — оно
4660
- * прижимается (`clampI16`). Ошибка при этом 6 см и только у вершины, стоящей ровно на дальней
4661
- * границе тайла.
4662
- */
4663
- declare const BUILDING_POS_SCALE = 8;
4664
- interface BuildingsMesh {
4665
- vertices: ArrayBuffer;
4666
- indices: ArrayBuffer;
4667
- /** Uint32Array: id фичи на каждый треугольник — для пикинга и подсветки. */
4668
- featureIds: ArrayBuffer;
4669
- vertexCount: number;
4670
- indexCount: number;
4671
- extent: number;
4672
- }
4673
- interface BuildingsOptions {
4674
- /**
4675
- * Радиус скругления углов в МЕТРАХ. Скругляется контур, а значит и стены, и
4676
- * крыша — она строится по тому же кольцу. Ноль (по умолчанию) — острые углы,
4677
- * как раньше.
4678
- */
4679
- cornerRadius?: number;
4680
- /** Максимум отрезков на дугу: меньше — дешевле и угловатее. */
4681
- cornerSegments?: number;
4682
- /**
4683
- * Сколько метров в одной единице тайла. Нужен, чтобы решать по РАЗМЕРУ: дом
4684
- * в сотню квадратов получает скатную крышу, торговый центр — плоскую. Без
4685
- * него один и тот же порог на разных зумах означал бы разные здания.
4686
- */
4687
- metersPerUnit?: number;
4688
- }
4689
- declare function generateBuildings(layer: VectorTileLayer, extent: number, filter?: Filter, options?: BuildingsOptions): BuildingsMesh | null;
4690
-
4691
4797
  /**
4692
4798
  * Скругление углов контура.
4693
4799
  *
@@ -5084,6 +5190,13 @@ interface LineMesh {
5084
5190
  indices: ArrayBuffer;
5085
5191
  vertexCount: number;
5086
5192
  indexCount: number;
5193
+ /**
5194
+ * id фичи НА ТРЕУГОЛЬНИК — тем же форматом, что у заливки и зданий.
5195
+ *
5196
+ * Нужен, чтобы вырезать линию из готового меша: под 3D-моделью прячется не только здание, но и
5197
+ * дорожки вокруг него, а их в наборе замен обычно больше всего.
5198
+ */
5199
+ featureIds: ArrayBuffer;
5087
5200
  }
5088
5201
  interface LineOptions {
5089
5202
  /**
@@ -5269,6 +5382,21 @@ interface SurfaceMesh {
5269
5382
  * островов: их рисуют отдельным проходом, только в глубину.
5270
5383
  */
5271
5384
  capIndexOffset: number;
5385
+ /**
5386
+ * ЧЬИ фичи попали в каждую фигуру: плоская таблица `[сколько, id, id, …]` в порядке фигур.
5387
+ *
5388
+ * Не «id на треугольник», как у зданий и заливки, и это не мелочь. Поверхность строится ПОСЛЕ
5389
+ * объединения (`unionShapes`): соседние газоны свариваются в один контур, и треугольник в общем
5390
+ * случае принадлежит не одной фиче, а всем, что в него слились. Прятать такую фигуру можно
5391
+ * только целиком и только если скрыты ВСЕ её фичи — иначе под 3D-моделью исчез бы и соседний
5392
+ * газон, которого никто не заменял.
5393
+ */
5394
+ shapeFeatures: ArrayBuffer;
5395
+ /**
5396
+ * Где лежат треугольники каждой фигуры: по четыре числа на фигуру —
5397
+ * `[начало, конец, начало крышек, конец крышек]` в индексах итогового буфера.
5398
+ */
5399
+ shapeRanges: ArrayBuffer;
5272
5400
  }
5273
5401
  /**
5274
5402
  * Нахлёст по линии разреза, единицы тайла.
@@ -5296,6 +5424,91 @@ interface SurfaceMesh {
5296
5424
  declare const SURFACE_CUT_BLEED = 1;
5297
5425
  declare function generateSurface(layer: VectorTileLayer, extent: number, filter: Filter | undefined, opts: SurfaceOptions): SurfaceMesh | null;
5298
5426
 
5427
+ /**
5428
+ * Объединение полигонов слоя в один контур — до построения меша.
5429
+ *
5430
+ * ЗАЧЕМ. В данных сплошного объекта не существует: газон вокруг квартала нарезан на десятки
5431
+ * полигонов, парк граничит с газоном того же слоя, река идёт цепочкой кусков. Каждый кусок
5432
+ * не знает о соседе и строит по своему краю борт, фаску и скругление — а на общей границе два
5433
+ * борта складываются в гребень посреди сплошной зелени.
5434
+ *
5435
+ * Раньше это лечил механизм `shared`: ребро, встретившееся у двух полигонов, считалось внутренним.
5436
+ * Он дёшев, но требует СОВПАДЕНИЯ ВЕРШИН до единицы, а тайлер упрощает каждый полигон отдельно,
5437
+ * и общая граница у двух соседей расходится. Совпадений не находится, и весь механизм молчит.
5438
+ *
5439
+ * Объединение снимает вопрос целиком: внутренних границ после него просто нет, а наружу выходит
5440
+ * один контур, по которому и строятся фаска, юбка и скругление.
5441
+ *
5442
+ * ЦЕНА. Булева операция дороже всего остального в генераторе, поэтому:
5443
+ * — объединяем ТОЛЬКО когда есть что объединять (два и более полигона);
5444
+ * — при отказе возвращаем исходные фигуры, а не роняем тайл: кривой контур в данных не повод
5445
+ * потерять слой целиком.
5446
+ */
5447
+ interface Shape {
5448
+ outer: Ring;
5449
+ holes: Ring[];
5450
+ lift?: number;
5451
+ }
5452
+
5453
+ /**
5454
+ * СШИВАНИЕ ПОЛИГОНА, РАЗРЕЗАННОГО ПО ТАЙЛАМ.
5455
+ *
5456
+ * Зачем. Дом, попавший на границу, тайлсервер отдаёт КУСКАМИ — по куску в каждый тайл, и каждый
5457
+ * обрезан по своему квадрату с буфером. Дальше движок строит из каждого куска свою геометрию, и
5458
+ * половинки обязаны сойтись на стыке идеально: скругление, фаска, стены, крыша — всё считается по
5459
+ * контуру, а контуры у кусков разные, потому что у каждого свой разрез. Сколько ни выравнивай
5460
+ * правила, остаётся угловатость на шве: разрез — это ложное ребро, и любая обработка, смотрящая на
5461
+ * соседние вершины, на нём врёт. Признака «это ребро ненастоящее» в векторных тайлах нет — так
5462
+ * записано и в их спецификации.
5463
+ *
5464
+ * Единственное честное решение — собрать дом обратно ДО того, как из него что-то строят.
5465
+ *
5466
+ * КАК. Не булевым объединением. Общие алгоритмы отсечения плохо переносят фигуры с совпадающими
5467
+ * границами: у них там вырожденные случаи и чувствительность к точности float. Тот же вывод сделан
5468
+ * в `union-subdivided-polygons` (SeaSketch), собранном ровно под эту задачу — склейку результатов
5469
+ * `ST_Subdivide`: сшивание по совпадающим вершинам вышло на ДВА ПОРЯДКА быстрее общего отсечения и
5470
+ * притом надёжнее.
5471
+ *
5472
+ * У нас случай ещё проще, и оба упрощения проверены на живых тайлах Душанбе:
5473
+ * • ложные рёбра известны точно — их создаёт обрезка, и мы помечаем их сами;
5474
+ * • координаты в тайле ЦЕЛЫЕ, а общая система — это `номер тайла × extent + локальная`, так что
5475
+ * совпадение вершин у соседей строгое, без допусков. Замер: из 48 зданий, попавших в два
5476
+ * соседних тайла, у 32 общие вершины совпали точно, у остальных куски и не пересекались.
5477
+ *
5478
+ * АЛГОРИТМ. Сперва самый частый и самый точный случай: если хоть один кусок пришёл БЕЗ ложных
5479
+ * рёбер, он и есть целый полигон — дом уместился в буфер своего тайла, и складывать нечего.
5480
+ *
5481
+ * Иначе — булево ОБЪЕДИНЕНИЕ кусков (`union.ts`, тот же код, которым сливаются поверхности).
5482
+ * Сначала здесь был свой обход: разрезать кольца по ложным рёбрам на цепочки и склеить цепочки по
5483
+ * совпадающим вершинам. На простых домах он работал, а на П-образном корпусе школы замыкал кольцо
5484
+ * РАНЬШЕ ВРЕМЕНИ — возвращал верхнюю перемычку вместо всего здания, и на карте от школы оставалась
5485
+ * одна полоса. Объединение такого сделать не может по построению: оно не выбирает, каким путём
5486
+ * идти, а складывает площади.
5487
+ *
5488
+ * Координаты сюда приходят в общей системе, но СДВИНУТЫМИ к одному тайлу — иначе числа в десятки
5489
+ * миллионов съели бы точность булевой операции.
5490
+ */
5491
+ /** Кусок полигона, приехавший из одного тайла. */
5492
+ interface PolygonPiece {
5493
+ /** Замкнутое кольцо в ОБЩЕЙ системе координат (последняя точка повторяет первую). */
5494
+ ring: Ring;
5495
+ /** Дыры куска, если есть. */
5496
+ holes?: Ring[];
5497
+ /**
5498
+ * Ложные рёбра: `cut[i]` — ребро от вершины `i` к вершине `i + 1`.
5499
+ *
5500
+ * Длина — на одну меньше числа точек замкнутого кольца, то есть по числу рёбер.
5501
+ */
5502
+ cut: boolean[];
5503
+ }
5504
+ /**
5505
+ * Собрать полигон из кусков.
5506
+ *
5507
+ * Возвращает кольца с дырами. `null` — собрать не удалось, и звать надо прежний путь «каждый кусок
5508
+ * сам по себе»: так бывает, когда дом тянется дальше загруженных тайлов и куска посередине нет.
5509
+ */
5510
+ declare function stitchPieces(pieces: PolygonPiece[]): Shape[] | null;
5511
+
5299
5512
  /**
5300
5513
  * Цель рендера с одной только глубиной — карта теней.
5301
5514
  *
@@ -5846,6 +6059,17 @@ declare class Map$1 extends Evented<MapEvents> {
5846
6059
  * Направление берётся у ключевого источника света (`setLight`), поэтому
5847
6060
  * двигать солнце и тень отдельно нельзя — и не нужно.
5848
6061
  */
6062
+ /**
6063
+ * ОТЛАДКА: красить каждый тайл своим цветом.
6064
+ *
6065
+ * Нужна для разбора стыков. Шов на границе тайлов по обычной картинке не читается: не понять,
6066
+ * обрывается ли геометрия одного тайла, лезет ли поверх соседний или между ними щель — а от
6067
+ * ответа зависит, где чинить. Подкраска отвечает на это сразу, и заодно видно, из какого тайла
6068
+ * приехал кусок после подстановки предком.
6069
+ *
6070
+ * Работает на заливках и поверхностях — именно на них шов и виден.
6071
+ */
6072
+ setDebugTiles(on: boolean): this;
5849
6073
  setShadows(shadows: Partial<ShadowSettings> | boolean): this;
5850
6074
  /**
5851
6075
  * Здание под точкой экрана.
@@ -6105,4 +6329,4 @@ declare class Map$1 extends Evented<MapEvents> {
6105
6329
  destroy(): void;
6106
6330
  }
6107
6331
 
6108
- export { type AnimationOptions, AssetLoader, type AssetLoaderOptions, BASE_SOURCE, BUILDING_HEIGHT_SCALE, BUILDING_POS_SCALE, BUILDING_VERTEX_STRIDE, type BuildingHit, type BuildingsMesh, CITY_STYLE, type CameraOptions, Circle, type CircleOptions, type CoverOptions, DEFAULT_ICONS, DEFAULT_LIGHT, DEFAULT_SHADOWS, DEFAULT_SKY, DEFAULT_STYLE, DepthTarget, type DeviceHints, EARTH_CIRCUMFERENCE, FILL_VERTEX_STRIDE, type Filter, type FitBoundsOptions, type FitViewport, type FogPlanes, GLOBE_MAX_PITCH, GLOBE_ZOOM_MAX, GLOBE_ZOOM_MIN, GLYPH_BORDER, GLYPH_SIZE, GROUND_SCALE, GeomType, type GestureOptions, type Glyph, type GlyphMetric, GlyphSource, type GpuClass, GroundArrows, IconSource, IndoorMask, type Interpolated, LEVEL_LIMIT, LINE_VERTEX_STRIDE, type LayerPlan, LayerRenderer, type LightSpec, type LinePlacement, type LngLat, LngLatBounds, type LngLatLike, MAX_LATITUDE, MODEL_VERTEX_STRIDE, Map$1 as Map, type MapEvents, MapObject, type MapObjectOptions, type MapOptions, Marker, type MarkerOptions, Model, ModelLayer, type ModelMesh, type ModelOptions, type ModelPrimitive, ObjectManager, type ObjectPaint, type ObjectPart, type Padding, type PlacedGlyph, type PlacedSymbol, Polygon, type PolygonOptions, Polyline, type PolylineOptions, type PolylineSegment, Popup, type PopupOptions, type Projection, type QualityChange, QualityGovernor, type QualityName, type QualityProfile, RELIEF_STYLE, RUNTIME_FILL_STRIDE, RUNTIME_LINE_STRIDE, RasterSource, type RasterSourceOptions, RasterTile, type RoundOptions, type RuntimeMesh, SDF_EDGE, SDF_PX, SOFT_STYLE, SPLIT_SEP, SURFACE_CUT_BLEED, SURFACE_LEVEL_SCALE, SURFACE_VERTEX_STRIDE, type ScreenPoint$1 as ScreenPoint, SdfAtlas, type ShadowSettings, type SkySpec, Style, type StyleLayerSpec, type StyleSpec, type SymbolHit, SymbolRenderer, THEMES, TILE_SIZE, type ThemeSpec, TileID, Transform, VectorTile, VectorTileFeature, VectorTileLayer, abbreviateStreet, addGround, altitudeFromMercatorZ, applyTheme, arrowLabelOffset, arrowVertices, buildRuntimeFill, buildRuntimeLine, cameraForBounds, circumferenceAtLatitude, clampLat, clampPixelRatio, classifyRenderer, clipLineToRect, coordinateDigits, coveringTiles, createGround, Map$1 as default, deviceHints, distToSegment, evaluateColor, evaluateNumber, extractFeature, featureLevel, fillFootprint, fogPlanes, footprintOf, formatHash, generateBuildings, generateFill, generateLine, generateSurface, generateSymbols, globeBasis, globeFlatMix, globeRadius, globeToLocal, groundAt, iconRotation, insideFootprint, latFromMercatorY, lngFromMercatorX, lngLatToUnit, matchesFilter, mercatorMetersPerTile, mercatorX, mercatorY, mercatorZFromAltitude, metersPerPixel, metersPerTile, nextQualityDown, parseGlb, parseGlbAsync, parseGlyphs, parseHash, patchUV, pickBuilding, pickFill, pitchIntent, pixelsPerMeter, placeAlongLine, pointInRing, qualityFor, qualityProfile, raySphere, resolveTemplate, roundRing, sdfFromAlpha, shapeText, splitBucketKey, splitByGround, splitPolygons, styleWithTheme, tileOriginMeters, tileUrl, toLngLat, unitToLngLat, worldSize };
6332
+ export { type AnimationOptions, AssetLoader, type AssetLoaderOptions, BASE_SOURCE, BUILDING_HEIGHT_SCALE, BUILDING_POS_SCALE, BUILDING_VERTEX_STRIDE, type BuildingHit, type BuildingsMesh, CITY_STYLE, type CameraOptions, Circle, type CircleOptions, type CoverOptions, DEFAULT_ICONS, DEFAULT_LIGHT, DEFAULT_SHADOWS, DEFAULT_SKY, DEFAULT_STYLE, DepthTarget, type DeviceHints, EARTH_CIRCUMFERENCE, FILL_VERTEX_STRIDE, type Filter, type FitBoundsOptions, type FitViewport, type FogPlanes, GLOBE_MAX_PITCH, GLOBE_ZOOM_MAX, GLOBE_ZOOM_MIN, GLYPH_BORDER, GLYPH_SIZE, GROUND_SCALE, GeomType, type GestureOptions, type Glyph, type GlyphMetric, GlyphSource, type GpuClass, GroundArrows, IconSource, IndoorMask, type Interpolated, LEVEL_LIMIT, LINE_VERTEX_STRIDE, type LayerPlan, LayerRenderer, type LightSpec, type LinePlacement, type LngLat, LngLatBounds, type LngLatLike, MAX_LATITUDE, MODEL_VERTEX_STRIDE, Map$1 as Map, type MapEvents, MapObject, type MapObjectOptions, type MapOptions, Marker, type MarkerOptions, Model, ModelLayer, type ModelMesh, type ModelOptions, type ModelPrimitive, ObjectManager, type ObjectPaint, type ObjectPart, type Padding, type PlacedGlyph, type PlacedSymbol, Polygon, type PolygonOptions, type PolygonPiece, Polyline, type PolylineOptions, type PolylineSegment, Popup, type PopupOptions, type Projection, type QualityChange, QualityGovernor, type QualityName, type QualityProfile, RELIEF_STYLE, RUNTIME_FILL_STRIDE, RUNTIME_LINE_STRIDE, RasterSource, type RasterSourceOptions, RasterTile, type RoundOptions, type RuntimeMesh, SDF_EDGE, SDF_PX, SOFT_STYLE, SPLIT_SEP, SURFACE_CUT_BLEED, SURFACE_LEVEL_SCALE, SURFACE_VERTEX_STRIDE, type ScreenPoint$1 as ScreenPoint, SdfAtlas, type ShadowSettings, type SkySpec, Style, type StyleLayerSpec, type StyleSpec, type SymbolHit, SymbolRenderer, THEMES, TILE_SIZE, type ThemeSpec, TileID, Transform, VectorTile, VectorTileFeature, VectorTileLayer, abbreviateStreet, addGround, altitudeFromMercatorZ, applyTheme, arrowLabelOffset, arrowVertices, buildRuntimeFill, buildRuntimeLine, cameraForBounds, circumferenceAtLatitude, clampLat, clampPixelRatio, classifyRenderer, clipLineToRect, coordinateDigits, coveringTiles, createGround, Map$1 as default, deviceHints, distToSegment, evaluateColor, evaluateNumber, extractFeature, featureLevel, fillFootprint, fogPlanes, footprintOf, formatHash, generateBuildings, generateFill, generateLine, generateSurface, generateSymbols, globeBasis, globeFlatMix, globeRadius, globeToLocal, groundAt, iconRotation, insideFootprint, latFromMercatorY, lngFromMercatorX, lngLatToUnit, matchesFilter, mercatorMetersPerTile, mercatorX, mercatorY, mercatorZFromAltitude, metersPerPixel, metersPerTile, nextQualityDown, parseGlb, parseGlbAsync, parseGlyphs, parseHash, patchUV, pickBuilding, pickFill, pitchIntent, pixelsPerMeter, placeAlongLine, pointInRing, qualityFor, qualityProfile, raySphere, resolveTemplate, roundRing, sdfFromAlpha, shapeText, splitBucketKey, splitByGround, splitPolygons, stitchPieces, styleWithTheme, tileOriginMeters, tileUrl, toLngLat, unitToLngLat, worldSize };