osmgl 0.7.2 → 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.cjs +76 -64
- package/dist/osmgl.cjs.map +1 -1
- package/dist/osmgl.d.cts +496 -152
- package/dist/osmgl.d.ts +496 -152
- package/dist/osmgl.global.js +86 -74
- package/dist/osmgl.js +76 -64
- package/dist/osmgl.js.map +1 -1
- package/package.json +55 -55
package/dist/osmgl.d.ts
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
|
-
/**
|
|
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
|
* и основным проходом, и проходом теней: иначе тень появится раньше здания
|
|
@@ -4350,6 +4524,14 @@ interface QualityProfile {
|
|
|
4350
4524
|
simpleGeometry: boolean;
|
|
4351
4525
|
}
|
|
4352
4526
|
declare const qualityProfile: (name: QualityName) => QualityProfile;
|
|
4527
|
+
/**
|
|
4528
|
+
* Класс GPU по строке рендерера.
|
|
4529
|
+
*
|
|
4530
|
+
* `unknown` — не признак слабости, а честное «не знаем»: Safari отдаёт всем одну и ту же строку,
|
|
4531
|
+
* Firefox её огрубляет, а Tor и Brave в строгом режиме не отдают вовсе. Поэтому неизвестность НЕ
|
|
4532
|
+
* должна ничего решать — она просто оставляет вывод за остальными признаками.
|
|
4533
|
+
*/
|
|
4534
|
+
type GpuClass = 'software' | 'weak' | 'strong' | 'unknown';
|
|
4353
4535
|
/** То, из чего делается вывод. Вынесено в аргумент, чтобы это можно было проверить тестом. */
|
|
4354
4536
|
interface DeviceHints {
|
|
4355
4537
|
/** Число логических ядер (`navigator.hardwareConcurrency`). */
|
|
@@ -4359,7 +4541,22 @@ interface DeviceHints {
|
|
|
4359
4541
|
/** Мобильное устройство: грубый указатель или явный признак от браузера. */
|
|
4360
4542
|
mobile: boolean;
|
|
4361
4543
|
devicePixelRatio: number;
|
|
4544
|
+
/** Класс видеокарты по строке рендерера, если её удалось прочитать. */
|
|
4545
|
+
gpu?: GpuClass;
|
|
4362
4546
|
}
|
|
4547
|
+
/**
|
|
4548
|
+
* Класс GPU по строке `UNMASKED_RENDERER_WEBGL`.
|
|
4549
|
+
*
|
|
4550
|
+
* Ровно тот же приём, на котором стоит `detect-gpu`: строка рендерера — единственное, что браузер
|
|
4551
|
+
* говорит о видеокарте, не заставляя ничего рисовать. Полноценная база моделей с замерами (как у
|
|
4552
|
+
* `detect-gpu`) сюда не поместится и устареет, поэтому распознаём только то, что решает исход:
|
|
4553
|
+
* программный растеризатор, заведомо слабое встроенное видео и заведомо сильные дискретные чипы.
|
|
4554
|
+
* Всё остальное — `unknown`, и решают ядра с памятью.
|
|
4555
|
+
*
|
|
4556
|
+
* Мерить бенчмарком на старте по-прежнему нельзя: это сотни миллисекунд ровно там, где важна первая
|
|
4557
|
+
* отрисовка. Строка бесплатна.
|
|
4558
|
+
*/
|
|
4559
|
+
declare function classifyRenderer(renderer: string): GpuClass;
|
|
4363
4560
|
/**
|
|
4364
4561
|
* Профиль по признакам устройства.
|
|
4365
4562
|
*
|
|
@@ -4381,6 +4578,101 @@ declare function deviceHints(): DeviceHints;
|
|
|
4381
4578
|
declare function clampPixelRatio(cssWidth: number, cssHeight: number, devicePixelRatio: number, profile: QualityProfile): number;
|
|
4382
4579
|
/** Следующий профиль вниз или null, если ниже некуда. */
|
|
4383
4580
|
declare function nextQualityDown(name: QualityName): QualityName | null;
|
|
4581
|
+
/** Решение контроллера: на какую ступень перейти и в какую сторону. */
|
|
4582
|
+
interface QualityChange {
|
|
4583
|
+
to: QualityName;
|
|
4584
|
+
direction: 'up' | 'down';
|
|
4585
|
+
/** Доля тяжёлых кадров, на которой решение принято, — для сообщения в консоль. */
|
|
4586
|
+
share: number;
|
|
4587
|
+
}
|
|
4588
|
+
/**
|
|
4589
|
+
* Кто решает, менять ли ступень качества.
|
|
4590
|
+
*
|
|
4591
|
+
* ЗАЧЕМ ОТДЕЛЬНЫМ КЛАССОМ. Логика тут вся в состоянии — окно кадров, счётчики попыток, прогрев, —
|
|
4592
|
+
* и ошибка в ней не падает, а проявляется миганием теней у пользователя. Отдельно её видно и можно
|
|
4593
|
+
* проверить тестом, подавая кадры прямо (см. `tests/quality.test.mjs`).
|
|
4594
|
+
*
|
|
4595
|
+
* УСТРОЙСТВО. Вниз — быстро и по доле тяжёлых кадров: тормоза видно сразу. Вверх — медленно, с
|
|
4596
|
+
* ГИСТЕРЕЗИСОМ (порог подъёма на порядок ниже порога спуска) и с ХРАПОВИКОМ: каждая неудачная
|
|
4597
|
+
* попытка удваивает требуемое время спокойствия, а после второй ступень закрывается насовсем.
|
|
4598
|
+
* Именно храповик даёт главное свойство — качели ГАРАНТИРОВАННО затухают, а не ходят вечно.
|
|
4599
|
+
*
|
|
4600
|
+
* Так же устроены адаптивные масштабы разрешения в игровых движках: гистерезис против дребезга и
|
|
4601
|
+
* ограниченное число проб вверх, чтобы «подкачка» качества не стала заметной сама по себе.
|
|
4602
|
+
*/
|
|
4603
|
+
declare class QualityGovernor {
|
|
4604
|
+
private current;
|
|
4605
|
+
private ceiling;
|
|
4606
|
+
/** Кадр дольше этого — тяжёлый. */
|
|
4607
|
+
private readonly slowMs;
|
|
4608
|
+
/** Кадр дольше этого весит втрое: сотня миллисекунд — это не «немного не успели». */
|
|
4609
|
+
private readonly verySlowMs;
|
|
4610
|
+
private ring;
|
|
4611
|
+
private at;
|
|
4612
|
+
private sum;
|
|
4613
|
+
private filled;
|
|
4614
|
+
/** Кадров подряд на текущей ступени (после прогрева). */
|
|
4615
|
+
private steady;
|
|
4616
|
+
private warmup;
|
|
4617
|
+
/** Неудачные попытки подъёма на ступень: имя → сколько раз сорвались. */
|
|
4618
|
+
private attempts;
|
|
4619
|
+
/** Пришли ли мы на текущую ступень подъёмом — только такой срыв считается неудачей. */
|
|
4620
|
+
private arrivedByUp;
|
|
4621
|
+
/** Последние измерения — запасная оценка шага развёртки. См. [[threshold]]. */
|
|
4622
|
+
private recent;
|
|
4623
|
+
private recentAt;
|
|
4624
|
+
private recentFilled;
|
|
4625
|
+
/** Измеренный шаг развёртки экрана, мс. Ноль — не измерен. */
|
|
4626
|
+
private refreshMs;
|
|
4627
|
+
constructor(current: QualityName, ceiling: QualityName,
|
|
4628
|
+
/** Кадр дольше этого — тяжёлый. */
|
|
4629
|
+
slowMs: number,
|
|
4630
|
+
/** Кадр дольше этого весит втрое: сотня миллисекунд — это не «немного не успели». */
|
|
4631
|
+
verySlowMs: number);
|
|
4632
|
+
/** Потолок, до которого разрешено подниматься сейчас. Опускается сам, когда ступень не даётся. */
|
|
4633
|
+
get limit(): QualityName;
|
|
4634
|
+
/** Сменили ступень снаружи (`setQuality`) — начать наблюдение заново. */
|
|
4635
|
+
reset(current: QualityName, ceiling: QualityName): void;
|
|
4636
|
+
/**
|
|
4637
|
+
* Очередной кадр. `busy` — едут ли тайлы: пока едут, кадры не считаются вовсе.
|
|
4638
|
+
*
|
|
4639
|
+
* Зум и панорама всегда дают всплеск — приезжают и разбираются новые тайлы, — и на нём порог
|
|
4640
|
+
* набирался за пару секунд у любой карты. Мерить надо УСТОЯВШУЮСЯ стоимость, а не стоимость
|
|
4641
|
+
* загрузки.
|
|
4642
|
+
*/
|
|
4643
|
+
frame(frameMs: number, busy: boolean): QualityChange | null;
|
|
4644
|
+
/**
|
|
4645
|
+
* Порог «тяжёлого кадра» с поправкой на ЭКРАН.
|
|
4646
|
+
*
|
|
4647
|
+
* Мерой служит интервал между кадрами, а порог был жёсткий — 32 мс, «медленнее тридцати в
|
|
4648
|
+
* секунду». Но тридцать в секунду бывает и потолком САМОГО экрана: развёртка 30 Гц, режим
|
|
4649
|
+
* энергосбережения, композитор, ограничивший вкладку. Там интервал ровно 33 мс не потому, что
|
|
4650
|
+
* карта не успевает, а потому, что чаще показывать некуда, — и здоровая машина уезжала до
|
|
4651
|
+
* `minimal`, а на границе порога ещё и раскачивалась. Проверено: на широком окне шаг оказался
|
|
4652
|
+
* ровно 33 мс, и профиль сходил на три ступени за шесть секунд.
|
|
4653
|
+
*
|
|
4654
|
+
* Шаг развёртки берём ИЗМЕРЕННЫЙ (`setRefresh`), а не выведенный из тех же кадров. Вывод по
|
|
4655
|
+
* минимуму здесь принципиально неоднозначен: машина, ровно пригвождённая к 40 мс, неотличима от
|
|
4656
|
+
* экрана на 25 Гц — в обоих случаях все интервалы одинаковы. Разводит их только замер на ПУСТЫХ
|
|
4657
|
+
* кадрах в начале жизни карты, когда рисовать ещё нечего и частота кадров равна развёртке.
|
|
4658
|
+
*
|
|
4659
|
+
* Минимум по недавним кадрам остаётся запасным вариантом — на случай, если замер не удался.
|
|
4660
|
+
* Порог ниже исходного не опускается: на экране 120 Гц требовать от карты 120 кадров незачем.
|
|
4661
|
+
*/
|
|
4662
|
+
private threshold;
|
|
4663
|
+
/**
|
|
4664
|
+
* Сообщить измеренный шаг развёртки экрана (мс между кадрами при пустой сцене).
|
|
4665
|
+
*
|
|
4666
|
+
* Заведомо неправдоподобное игнорируем: быстрее 240 Гц экранов у нас нет, а всё, что медленнее
|
|
4667
|
+
* 20 кадров в секунду, — это уже не развёртка, а неудавшийся замер.
|
|
4668
|
+
*/
|
|
4669
|
+
setRefresh(ms: number): void;
|
|
4670
|
+
private down;
|
|
4671
|
+
private up;
|
|
4672
|
+
private moveTo;
|
|
4673
|
+
/** Забыть накопленное: после смены ступени прежние кадры относятся к другому профилю. */
|
|
4674
|
+
private restart;
|
|
4675
|
+
}
|
|
4384
4676
|
|
|
4385
4677
|
/**
|
|
4386
4678
|
* Кусок предка, приходящийся на этот тайл: сдвиг и масштаб текстурной
|
|
@@ -4502,74 +4794,6 @@ declare function placeAlongLine(line: ScreenPoint[], glyphs: GlyphMetric[], text
|
|
|
4502
4794
|
*/
|
|
4503
4795
|
declare function clipLineToRect(line: ScreenPoint[], width: number, height: number, margin: number): ScreenPoint[][];
|
|
4504
4796
|
|
|
4505
|
-
/**
|
|
4506
|
-
* Генератор геометрии зданий: экструзия полигонов слоя `building` (схема OpenMapTiles v3).
|
|
4507
|
-
* Работает в воркере, отдаёт готовые типизированные массивы — они уходят в главный
|
|
4508
|
-
* поток transfer'ом (без копирования) и грузятся в GPU как есть.
|
|
4509
|
-
*
|
|
4510
|
-
* Формат вершины (stride 18 байт):
|
|
4511
|
-
* a_pos 2 × Int16 off 0 координаты тайла [0..extent]
|
|
4512
|
-
* a_height 1 × Uint16 off 4 высота вершины в метрах × 4 (до 16383 м, шаг 0.25)
|
|
4513
|
-
* a_tint 1 × Uint8 off 6 оттенок здания (одинаков у всех его вершин)
|
|
4514
|
-
* a_ao 1 × Uint8 off 7 0 — основание, 255 — верх
|
|
4515
|
-
* a_normal 3 × Int8n off 8 нормаль
|
|
4516
|
-
* a_kind 1 × Uint8 off 11 тип поверхности и класс фасада
|
|
4517
|
-
* a_wall 3 × Uint16 off 12 фасад: смещение вдоль грани, её ширина и высота (метры × 4)
|
|
4518
|
-
*
|
|
4519
|
-
* Высота ушла из Float32 в Uint16 ради места под a_tint: без разброса оттенка
|
|
4520
|
-
* квартал выглядит одной сплошной массой.
|
|
4521
|
-
*
|
|
4522
|
-
* `a_wall` появился ради РОВНОЙ раскладки окон. Сначала координата вдоль стены
|
|
4523
|
-
* считалась в шейдере как проекция позиции на её направление — сетка тогда общая
|
|
4524
|
-
* на всю карту, и грань режет её где придётся: у угла дома получается половина
|
|
4525
|
-
* окна, а простенки у разных стен разной ширины. Ширина и высота грани позволяют
|
|
4526
|
-
* ВПИСАТЬ сетку в неё: поля по краям, целое число ячеек, окно целиком.
|
|
4527
|
-
*/
|
|
4528
|
-
declare const BUILDING_VERTEX_STRIDE = 18;
|
|
4529
|
-
/** Множитель упаковки высоты в Uint16. */
|
|
4530
|
-
declare const BUILDING_HEIGHT_SCALE = 32;
|
|
4531
|
-
/**
|
|
4532
|
-
* Множитель упаковки ПОЛОЖЕНИЯ вершины: сколько единиц Int16 приходится на единицу тайла.
|
|
4533
|
-
*
|
|
4534
|
-
* Было единица — то есть 0.47 м на z14, потому что координаты в MVT целые и вершину писали как
|
|
4535
|
-
* есть. Пока углы дома были прямыми, этого хватало: вершина и так стояла в узле сетки. Со
|
|
4536
|
-
* СКРУГЛЕНИЕМ хватать перестало — дуга радиусом 1.6 м это семь точек в пределах трёх единиц тайла,
|
|
4537
|
-
* и округление сажает их на ту же сетку: вместо дуги выходит лесенка со ступенью в полметра, она же
|
|
4538
|
-
* «угловатость» на ближнем зуме.
|
|
4539
|
-
*
|
|
4540
|
-
* Восемь единиц на тайловую — это 5.9 см, и дуга снова читается дугой. Потолок: тайл 0..4096, при
|
|
4541
|
-
* ×8 это 0..32768, и последнее значение на единицу больше, чем помещается в Int16, — оно
|
|
4542
|
-
* прижимается (`clampI16`). Ошибка при этом 6 см и только у вершины, стоящей ровно на дальней
|
|
4543
|
-
* границе тайла.
|
|
4544
|
-
*/
|
|
4545
|
-
declare const BUILDING_POS_SCALE = 8;
|
|
4546
|
-
interface BuildingsMesh {
|
|
4547
|
-
vertices: ArrayBuffer;
|
|
4548
|
-
indices: ArrayBuffer;
|
|
4549
|
-
/** Uint32Array: id фичи на каждый треугольник — для пикинга и подсветки. */
|
|
4550
|
-
featureIds: ArrayBuffer;
|
|
4551
|
-
vertexCount: number;
|
|
4552
|
-
indexCount: number;
|
|
4553
|
-
extent: number;
|
|
4554
|
-
}
|
|
4555
|
-
interface BuildingsOptions {
|
|
4556
|
-
/**
|
|
4557
|
-
* Радиус скругления углов в МЕТРАХ. Скругляется контур, а значит и стены, и
|
|
4558
|
-
* крыша — она строится по тому же кольцу. Ноль (по умолчанию) — острые углы,
|
|
4559
|
-
* как раньше.
|
|
4560
|
-
*/
|
|
4561
|
-
cornerRadius?: number;
|
|
4562
|
-
/** Максимум отрезков на дугу: меньше — дешевле и угловатее. */
|
|
4563
|
-
cornerSegments?: number;
|
|
4564
|
-
/**
|
|
4565
|
-
* Сколько метров в одной единице тайла. Нужен, чтобы решать по РАЗМЕРУ: дом
|
|
4566
|
-
* в сотню квадратов получает скатную крышу, торговый центр — плоскую. Без
|
|
4567
|
-
* него один и тот же порог на разных зумах означал бы разные здания.
|
|
4568
|
-
*/
|
|
4569
|
-
metersPerUnit?: number;
|
|
4570
|
-
}
|
|
4571
|
-
declare function generateBuildings(layer: VectorTileLayer, extent: number, filter?: Filter, options?: BuildingsOptions): BuildingsMesh | null;
|
|
4572
|
-
|
|
4573
4797
|
/**
|
|
4574
4798
|
* Скругление углов контура.
|
|
4575
4799
|
*
|
|
@@ -4966,6 +5190,13 @@ interface LineMesh {
|
|
|
4966
5190
|
indices: ArrayBuffer;
|
|
4967
5191
|
vertexCount: number;
|
|
4968
5192
|
indexCount: number;
|
|
5193
|
+
/**
|
|
5194
|
+
* id фичи НА ТРЕУГОЛЬНИК — тем же форматом, что у заливки и зданий.
|
|
5195
|
+
*
|
|
5196
|
+
* Нужен, чтобы вырезать линию из готового меша: под 3D-моделью прячется не только здание, но и
|
|
5197
|
+
* дорожки вокруг него, а их в наборе замен обычно больше всего.
|
|
5198
|
+
*/
|
|
5199
|
+
featureIds: ArrayBuffer;
|
|
4969
5200
|
}
|
|
4970
5201
|
interface LineOptions {
|
|
4971
5202
|
/**
|
|
@@ -5151,6 +5382,21 @@ interface SurfaceMesh {
|
|
|
5151
5382
|
* островов: их рисуют отдельным проходом, только в глубину.
|
|
5152
5383
|
*/
|
|
5153
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;
|
|
5154
5400
|
}
|
|
5155
5401
|
/**
|
|
5156
5402
|
* Нахлёст по линии разреза, единицы тайла.
|
|
@@ -5178,6 +5424,91 @@ interface SurfaceMesh {
|
|
|
5178
5424
|
declare const SURFACE_CUT_BLEED = 1;
|
|
5179
5425
|
declare function generateSurface(layer: VectorTileLayer, extent: number, filter: Filter | undefined, opts: SurfaceOptions): SurfaceMesh | null;
|
|
5180
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
|
+
|
|
5181
5512
|
/**
|
|
5182
5513
|
* Цель рендера с одной только глубиной — карта теней.
|
|
5183
5514
|
*
|
|
@@ -5534,16 +5865,8 @@ declare class Map$1 extends Evented<MapEvents> {
|
|
|
5534
5865
|
* собой заменяли, — см. `setObjects3DEnabled`.
|
|
5535
5866
|
*/
|
|
5536
5867
|
private objects3dEnabled;
|
|
5537
|
-
/**
|
|
5538
|
-
|
|
5539
|
-
private readonly frameRing;
|
|
5540
|
-
private ringAt;
|
|
5541
|
-
private ringSum;
|
|
5542
|
-
private ringFilled;
|
|
5543
|
-
/** Кадров на текущей ступени — чтобы не проситься выше сразу после смены. */
|
|
5544
|
-
private steadyFrames;
|
|
5545
|
-
/** Профиль, выбранный по железу: выше него не поднимаемся никогда. */
|
|
5546
|
-
private qualityCeiling;
|
|
5868
|
+
/** Кто решает, менять ли ступень качества. Вся логика окна и храповика — в нём. */
|
|
5869
|
+
private governor;
|
|
5547
5870
|
/** Время прошлого кадра и сколько кадров идёт подряд — для честного замера. */
|
|
5548
5871
|
private lastFrameAt;
|
|
5549
5872
|
private continuousFrames;
|
|
@@ -5554,6 +5877,19 @@ declare class Map$1 extends Evented<MapEvents> {
|
|
|
5554
5877
|
/** Слепок прошлого набора этажей — чтобы не слать событие каждый кадр. */
|
|
5555
5878
|
private lastIndoorKey;
|
|
5556
5879
|
constructor(options: MapOptions);
|
|
5880
|
+
/**
|
|
5881
|
+
* Замерить шаг развёртки экрана — по пустым кадрам в самом начале жизни карты.
|
|
5882
|
+
*
|
|
5883
|
+
* Автоснижение судит о тормозах по интервалу между кадрами, и без этого числа сравнивать его не
|
|
5884
|
+
* с чем. Отдельный замер нужен потому, что по рабочим кадрам развёртку не вычислить: экран на
|
|
5885
|
+
* 30 Гц и машина, ровно вдвое не успевающая на 60 Гц, дают одинаковые 33 мс. А вот пока рисовать
|
|
5886
|
+
* нечего — тайлы ещё едут, сцена пуста, — частота кадров равна развёртке, и это тот единственный
|
|
5887
|
+
* момент, когда её видно.
|
|
5888
|
+
*
|
|
5889
|
+
* Обработчик НИЧЕГО не рисует: он только запоминает отметки времени. Своих кадров он не заказывает
|
|
5890
|
+
* сверх этих двенадцати и заканчивается за пятую долю секунды.
|
|
5891
|
+
*/
|
|
5892
|
+
private measureRefresh;
|
|
5557
5893
|
private initGL;
|
|
5558
5894
|
private initSource;
|
|
5559
5895
|
/** Имя источника размещений 3D-объектов (если они вообще включены). */
|
|
@@ -5723,6 +6059,17 @@ declare class Map$1 extends Evented<MapEvents> {
|
|
|
5723
6059
|
* Направление берётся у ключевого источника света (`setLight`), поэтому
|
|
5724
6060
|
* двигать солнце и тень отдельно нельзя — и не нужно.
|
|
5725
6061
|
*/
|
|
6062
|
+
/**
|
|
6063
|
+
* ОТЛАДКА: красить каждый тайл своим цветом.
|
|
6064
|
+
*
|
|
6065
|
+
* Нужна для разбора стыков. Шов на границе тайлов по обычной картинке не читается: не понять,
|
|
6066
|
+
* обрывается ли геометрия одного тайла, лезет ли поверх соседний или между ними щель — а от
|
|
6067
|
+
* ответа зависит, где чинить. Подкраска отвечает на это сразу, и заодно видно, из какого тайла
|
|
6068
|
+
* приехал кусок после подстановки предком.
|
|
6069
|
+
*
|
|
6070
|
+
* Работает на заливках и поверхностях — именно на них шов и виден.
|
|
6071
|
+
*/
|
|
6072
|
+
setDebugTiles(on: boolean): this;
|
|
5726
6073
|
setShadows(shadows: Partial<ShadowSettings> | boolean): this;
|
|
5727
6074
|
/**
|
|
5728
6075
|
* Здание под точкой экрана.
|
|
@@ -5826,10 +6173,9 @@ declare class Map$1 extends Evented<MapEvents> {
|
|
|
5826
6173
|
*
|
|
5827
6174
|
* Определение по признакам устройства ошибается в обе стороны: телефон с
|
|
5828
6175
|
* восемью ядрами может нести слабый GPU, а браузер — врать про плотность.
|
|
5829
|
-
* Поэтому профиль ещё и проверяется делом.
|
|
5830
|
-
*
|
|
5831
|
-
*
|
|
5832
|
-
* чем стабильно работающая карта.
|
|
6176
|
+
* Поэтому профиль ещё и проверяется делом. Решение принимает `QualityGovernor` — там же и
|
|
6177
|
+
* защита от качелей: гистерезис, прогрев после смены и храповик на попытки подъёма. Здесь
|
|
6178
|
+
* остаётся только применить решение.
|
|
5833
6179
|
*
|
|
5834
6180
|
* ДВА ОГРАНИЧЕНИЯ, без которых от этого механизма больше вреда, чем пользы.
|
|
5835
6181
|
*
|
|
@@ -5837,17 +6183,15 @@ declare class Map$1 extends Evented<MapEvents> {
|
|
|
5837
6183
|
* геометрии. Разрешение пользователь видит сразу и целиком: подписи и значки после понижения
|
|
5838
6184
|
* рисуются в буфер меньше экрана, браузер растягивает его обратно, и карта становится мыльной.
|
|
5839
6185
|
* Упрощение геометрии отнимает у поверхностей фаску, подъём и скругление — приподнятый газон
|
|
5840
|
-
* становится плоским пятном. Обратно
|
|
5841
|
-
* навсегда. Режем РАБОТУ (детализацию, тени, число тайлов и воркеров) — её потерю видно куда
|
|
5842
|
-
*
|
|
6186
|
+
* становится плоским пятном. Обратно эти две вещи не поднимаются, значит и то и другое осталось
|
|
6187
|
+
* бы навсегда. Режем РАБОТУ (детализацию, тени, число тайлов и воркеров) — её потерю видно куда
|
|
6188
|
+
* меньше, и она обратима. Так же поступают MapLibre и Mapbox: `pixelRatio` у них не адаптивный.
|
|
5843
6189
|
*
|
|
5844
6190
|
* Второе: пока едут тайлы, кадры не считаются вовсе. Зум и панорама всегда
|
|
5845
6191
|
* дают всплеск — приезжают и разбираются новые тайлы, — и на нём порог
|
|
5846
6192
|
* набирался за пару секунд у любой карты. Мерить надо УСТОЯВШУЮСЯ стоимость,
|
|
5847
6193
|
* а не стоимость загрузки.
|
|
5848
6194
|
*/
|
|
5849
|
-
/** Забыть накопленное: после смены ступени прежние кадры относятся к другому профилю. */
|
|
5850
|
-
private resetFrameWindow;
|
|
5851
6195
|
private checkFrameBudget;
|
|
5852
6196
|
getShadows(): ShadowSettings;
|
|
5853
6197
|
/**
|
|
@@ -5985,4 +6329,4 @@ declare class Map$1 extends Evented<MapEvents> {
|
|
|
5985
6329
|
destroy(): void;
|
|
5986
6330
|
}
|
|
5987
6331
|
|
|
5988
|
-
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, 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 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, 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 };
|