isard 1.4.0 → 1.6.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/CHANGELOG.md +220 -2
- package/README.md +23 -7
- package/dist/basemap/furniture.d.ts +8 -0
- package/dist/basemap/furniture.js +26 -0
- package/dist/basemap/furniture.js.map +1 -0
- package/dist/basemap/trees.d.ts +35 -8
- package/dist/basemap/trees.js +105 -52
- package/dist/basemap/trees.js.map +1 -1
- package/dist/basemap/vectorstyle.d.ts +9 -3
- package/dist/basemap/vectorstyle.js +5 -6
- package/dist/basemap/vectorstyle.js.map +1 -1
- package/dist/basemap/vectortiles/context.d.ts +46 -0
- package/dist/basemap/vectortiles/context.js +6 -0
- package/dist/basemap/vectortiles/context.js.map +1 -0
- package/dist/basemap/vectortiles/extrusions.d.ts +15 -0
- package/dist/basemap/vectortiles/extrusions.js +61 -0
- package/dist/basemap/vectortiles/extrusions.js.map +1 -0
- package/dist/basemap/vectortiles/labels.d.ts +25 -0
- package/dist/basemap/vectortiles/labels.js +250 -0
- package/dist/basemap/vectortiles/labels.js.map +1 -0
- package/dist/basemap/vectortiles/lamps.d.ts +23 -0
- package/dist/basemap/vectortiles/lamps.js +90 -0
- package/dist/basemap/vectortiles/lamps.js.map +1 -0
- package/dist/basemap/vectortiles/requests.d.ts +28 -0
- package/dist/basemap/vectortiles/requests.js +74 -0
- package/dist/basemap/vectortiles/requests.js.map +1 -0
- package/dist/basemap/vectortiles/street-wind.d.ts +19 -0
- package/dist/basemap/vectortiles/street-wind.js +133 -0
- package/dist/basemap/vectortiles/street-wind.js.map +1 -0
- package/dist/basemap/vectortiles/style.d.ts +47 -0
- package/dist/basemap/vectortiles/style.js +141 -0
- package/dist/basemap/vectortiles/style.js.map +1 -0
- package/dist/basemap/vectortiles/tiles.d.ts +34 -0
- package/dist/basemap/vectortiles/tiles.js +62 -0
- package/dist/basemap/vectortiles/tiles.js.map +1 -0
- package/dist/basemap/vectortiles/trees.d.ts +28 -0
- package/dist/basemap/vectortiles/trees.js +178 -0
- package/dist/basemap/vectortiles/trees.js.map +1 -0
- package/dist/basemap/vectortiles/vectors.d.ts +37 -0
- package/dist/basemap/vectortiles/vectors.js +231 -0
- package/dist/basemap/vectortiles/vectors.js.map +1 -0
- package/dist/basemap/vectortiles.d.ts +49 -96
- package/dist/basemap/vectortiles.js +99 -774
- package/dist/basemap/vectortiles.js.map +1 -1
- package/dist/basemap/workerpool.js +25 -6
- package/dist/basemap/workerpool.js.map +1 -1
- package/dist/basemap.worker.js +2 -2
- package/dist/basemap.worker.js.map +14 -12
- package/dist/bind/layers.js +1 -0
- package/dist/bind/layers.js.map +1 -1
- package/dist/data/collada.d.ts +19 -0
- package/dist/data/collada.js +319 -0
- package/dist/data/collada.js.map +1 -0
- package/dist/data/ifc.d.ts +100 -0
- package/dist/data/ifc.js +372 -0
- package/dist/data/ifc.js.map +1 -0
- package/dist/decoder.worker.js +5 -4
- package/dist/decoder.worker.js.map +8 -6
- package/dist/engine/decoders.d.ts +4 -8
- package/dist/engine/decoders.js +29 -2
- package/dist/engine/decoders.js.map +1 -1
- package/dist/formats.d.ts +7 -2
- package/dist/formats.js +7 -2
- package/dist/formats.js.map +1 -1
- package/dist/index.d.ts +15 -2
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/isard_bg.wasm +0 -0
- package/dist/isard_core_bg.wasm +0 -0
- package/dist/isard_grid_bg.wasm +0 -0
- package/dist/isard_tess_bg.wasm +0 -0
- package/dist/layers/extrusions.d.ts +10 -0
- package/dist/layers/extrusions.js +28 -2
- package/dist/layers/extrusions.js.map +1 -1
- package/dist/layers/flow.d.ts +9 -2
- package/dist/layers/flow.js +51 -10
- package/dist/layers/flow.js.map +1 -1
- package/dist/layers/layers.d.ts +12 -0
- package/dist/layers/layers.js +44 -1
- package/dist/layers/layers.js.map +1 -1
- package/dist/layers/panoramas.d.ts +2 -0
- package/dist/layers/panoramas.js +27 -6
- package/dist/layers/panoramas.js.map +1 -1
- package/dist/layers/photos.d.ts +48 -0
- package/dist/layers/photos.js +140 -0
- package/dist/layers/photos.js.map +1 -0
- package/dist/layers/symbols.d.ts +5 -1
- package/dist/layers/symbols.js +111 -32
- package/dist/layers/symbols.js.map +1 -1
- package/dist/layers/trees.d.ts +28 -0
- package/dist/layers/trees.js +51 -0
- package/dist/layers/trees.js.map +1 -0
- package/dist/layers/vectors.d.ts +28 -2
- package/dist/layers/vectors.js +81 -7
- package/dist/layers/vectors.js.map +1 -1
- package/dist/map/layer-spec.d.ts +3 -0
- package/dist/map/layer-spec.js +2 -0
- package/dist/map/layer-spec.js.map +1 -1
- package/dist/map/workers.js +3 -0
- package/dist/map/workers.js.map +1 -1
- package/dist/map.d.ts +8 -0
- package/dist/map.js +15 -2
- package/dist/map.js.map +1 -1
- package/dist/panoramax.d.ts +49 -0
- package/dist/panoramax.js +71 -0
- package/dist/panoramax.js.map +1 -0
- package/dist/react/Layer.d.ts +1 -0
- package/dist/react/Layer.js.map +1 -1
- package/dist/react/VectorGeometry.d.ts +5 -0
- package/dist/react/VectorGeometry.js +12 -4
- package/dist/react/VectorGeometry.js.map +1 -1
- package/dist/util/gltf.d.ts +9 -0
- package/dist/util/gltf.js +27 -0
- package/dist/util/gltf.js.map +1 -0
- package/dist/util/read.d.ts +4 -0
- package/dist/util/read.js +28 -0
- package/dist/util/read.js.map +1 -0
- package/dist/util/roofs.d.ts +10 -0
- package/dist/util/roofs.js +30 -0
- package/dist/util/roofs.js.map +1 -0
- package/dist/wasm/isard.d.ts +74 -22
- package/dist/wasm/isard.js +153 -22
- package/dist/wasm/isard_core.d.ts +62 -22
- package/dist/wasm/isard_core.js +129 -22
- package/dist/wasm/isard_tess.d.ts +6 -3
- package/dist/wasm/isard_tess.js +27 -4
- package/dist/workers/basemap/geometry.d.ts +38 -22
- package/dist/workers/basemap/labels.d.ts +14 -1
- package/dist/workers/basemap/lamps.d.ts +10 -0
- package/dist/workers/basemap/street.d.ts +1 -1
- package/dist/workers/basemap/trees.d.ts +3 -1
- package/dist/workers/basemap.worker.d.ts +43 -3
- package/dist/workers/basemap.worker.js +14 -2
- package/dist/workers/basemap.worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiles.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/tiles.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The tiles of the vector layers (`VectorTiles`): the tiles around the view, their keys, the order they are asked\n * for in, and the defaults the layers share.\n */\n\nimport type { GeoMap } from '../../map.ts';\nimport { mercatorX, mercatorY } from '../../util/geo.ts';\nimport type { Camera } from '../../wasm/isard.js';\nimport type { Priority } from '../../workers/basemap.worker.ts';\n\n/** A tile: its level and its column and row at that level */\nexport type TileTriple = [z: number, x: number, y: number];\n\n/** Street level: the zoom the extrusions, the streets' wind and the trees start at by default */\nexport const STREET_ZOOM = 15;\n\n/** Tiles of a layer that follows the view, by default (the extrusions', the labels') */\nexport const MAX_TILES = 36;\n\n/** Tiles nearest to the center asked for first: the others wait (for the raster tiles, for instance) */\nexport const NEAR_TILES = 4;\n\n/** Milliseconds between two updates of the tiles of a layer while the camera moves */\nexport const VECTOR_MOVE_REFRESH_MS = 250;\n\n/** A tile's key, `z/x/y` */\nexport const tileKey = (z: number, x: number, y: number): string => `${z}/${x}/${y}`;\n\n/** The tile of a key `z/x/y` (zeros for the numbers it lacks) */\nexport const parseTileKey = (key: string): TileTriple => {\n const [z = 0, x = 0, y = 0] = key.split('/').map(Number);\n\n return [z, x, y];\n};\n\n/** The tiles of the engine's flat list of z, x, y triples */\nexport const tileTriples = (list: Uint32Array): TileTriple[] =>\n Array.from(\n { length: Math.floor(list.length / 3) },\n (_, i): TileTriple => [list[i * 3] ?? 0, list[i * 3 + 1] ?? 0, list[i * 3 + 2] ?? 0],\n );\n\n/** The priority of the `index`th tile asked for, the nearest first: `near` for the first `NEAR_TILES`, `far` after */\nexport const nearPriority = (index: number, near: Priority = 'auto', far: Priority = 'low'): Priority =>\n index < NEAR_TILES ? near : far;\n\n/** A tile's column at level `z` brought back into the world (the columns past the antimeridian are those of its other\n * side) */\nexport const wrapColumn = (x: number, z: number): number => {\n const n = 2 ** z;\n\n return ((x % n) + n) % n;\n};\n\n/**\n * The tiles of level `z` in view, within a window around the center (a tilted view's bounds reach far), the\n * `maxTiles` nearest to the center first. Across the antimeridian, the window's columns go on round the world (the\n * view's bounds, which stop at ±180°, no longer limit them)\n */\nexport const tilesAround = (map: GeoMap, camera: Camera, z: number, maxTiles: number): [x: number, y: number][] => {\n const n = 2 ** z;\n const [west, south, east, north] = map.getBounds();\n const tx = (lon: number) => Math.floor(mercatorX(lon) * n);\n const ty = (lat: number) => Math.floor(mercatorY(lat) * n);\n const [cx, cy] = [mercatorX(camera.center[0]) * n, mercatorY(camera.center[1]) * n];\n const reach = Math.ceil(Math.sqrt(maxTiles)) + 2;\n const [left, right] = [Math.floor(cx) - reach, Math.floor(cx) + reach];\n const across = left < 0 || right > n - 1;\n const [x0, x1] = across ? [left, right] : [Math.max(left, tx(west)), Math.min(right, tx(east))];\n const [y0, y1] = [Math.max(0, ty(north), Math.floor(cy) - reach), Math.min(n - 1, ty(south), Math.floor(cy) + reach)];\n const wanted = Array.from({ length: Math.max(0, y1 - y0 + 1) }, (_, j) => y0 + j).flatMap((y) =>\n Array.from({ length: Math.max(0, x1 - x0 + 1) }, (_, i): [number, number] => [x0 + i, y]),\n );\n\n wanted.sort((a, b) => Math.hypot(a[0] + 0.5 - cx, a[1] + 0.5 - cy) - Math.hypot(b[0] + 0.5 - cx, b[1] + 0.5 - cy));\n\n // Each tile once (at a low level, the window can go round the whole world)\n const seen = new Set<string>();\n\n return wanted\n .map(([x, y]): [number, number] => [wrapColumn(x, z), y])\n .filter(([x, y]) => {\n const k = `${x}/${y}`;\n\n if (seen.has(k)) return false;\n seen.add(k);\n\n return true;\n })\n .slice(0, maxTiles);\n};\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** The trees of a vector basemap (`VectorTiles.trees`): 3D models scattered by the workers over its woods and grass */
|
|
2
|
+
import type { Layer, ModelLayer } from '../../layers/layers.ts';
|
|
3
|
+
import type { GeoMap } from '../../map.ts';
|
|
4
|
+
import { type TreeColors } from '../trees.ts';
|
|
5
|
+
import type { StyleLayer } from '../vectorstyle.ts';
|
|
6
|
+
import type { VectorTilesContext } from './context.ts';
|
|
7
|
+
/** Metres in a degree of latitude (and of longitude at the equator), near enough for the trees' distances */
|
|
8
|
+
export declare const METRES_PER_DEGREE = 111320;
|
|
9
|
+
/** The options of `VectorTiles.trees` */
|
|
10
|
+
export interface TreesOptions {
|
|
11
|
+
layers?: (layer: StyleLayer) => boolean;
|
|
12
|
+
spacing?: number | ((layer: StyleLayer) => number);
|
|
13
|
+
minZoom?: number;
|
|
14
|
+
maxTiles?: number;
|
|
15
|
+
maxTrees?: number;
|
|
16
|
+
maxInstances?: number;
|
|
17
|
+
colors?: Partial<TreeColors>;
|
|
18
|
+
url?: string;
|
|
19
|
+
data?: ArrayBuffer | ArrayBufferView<ArrayBuffer>;
|
|
20
|
+
before?: Layer;
|
|
21
|
+
}
|
|
22
|
+
/** The ground under the camera: east and north metres from the view's center, and its distance from it (the camera
|
|
23
|
+
* stands behind the center of a tilted view, `FOV` its field of view) */
|
|
24
|
+
export declare const groundUnderCamera: (map: GeoMap) => [east: number, north: number, distance: number];
|
|
25
|
+
/** What follows the camera as it moves: `send` called again once it has gone `RESEND_SHARE` of `radius` metres (or
|
|
26
|
+
* turned or zoomed as much), not at every frame of a drag */
|
|
27
|
+
export declare const followWhenMoved: (map: GeoMap, radius: (zoom: number) => number, send: () => void) => (() => void);
|
|
28
|
+
export declare const trees: (context: VectorTilesContext, options?: TreesOptions) => ModelLayer;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/** The trees of a vector basemap (`VectorTiles.trees`): 3D models scattered by the workers over its woods and grass */
|
|
2
|
+
import { coniferModel, isWoodland, TREE_NUMBERS, treeModel, treeSpacing } from "../trees.js";
|
|
3
|
+
import { TileRequests } from "./requests.js";
|
|
4
|
+
import { nearPriority, STREET_ZOOM, tileKey, tilesAround } from "./tiles.js";
|
|
5
|
+
/** Metres around the view's center where every tree is drawn in full at zoom 16 (twice as far a zoom level out);
|
|
6
|
+
* past them, simplified (`treeModel(…, true)`) */
|
|
7
|
+
const TREES_NEAR_METRES = 350;
|
|
8
|
+
/** The engine's vertical field of view (radians, `camera::FOV`): where the camera stands behind the view's center */
|
|
9
|
+
const FOV = 0.6435011087932844;
|
|
10
|
+
/** How much denser the simplified trees far away stay than the full ones would (four times fewer triangles each): a
|
|
11
|
+
* tree twice as far kept as often */
|
|
12
|
+
const FAR_DENSITY = 4;
|
|
13
|
+
/** The simplified trees drawn at most, for so many full ones (`maxInstances`) */
|
|
14
|
+
const FAR_INSTANCES = 3;
|
|
15
|
+
/** While the camera moves, the trees chosen again once it has gone this share of the full trees' radius (or turned
|
|
16
|
+
* or zoomed as much): going through the tiles' trees at every frame of a drag would hold the main thread */
|
|
17
|
+
const RESEND_SHARE = 0.05;
|
|
18
|
+
/** Metres in a degree of latitude (and of longitude at the equator), near enough for the trees' distances */
|
|
19
|
+
export const METRES_PER_DEGREE = 111320;
|
|
20
|
+
/** The ground under the camera: east and north metres from the view's center, and its distance from it (the camera
|
|
21
|
+
* stands behind the center of a tilted view, `FOV` its field of view) */
|
|
22
|
+
export const groundUnderCamera = (map) => {
|
|
23
|
+
const { pitch, bearing } = map.getCamera();
|
|
24
|
+
const back = ((0.5 * map.getCanvas().clientHeight) / Math.tan(FOV / 2)) *
|
|
25
|
+
Math.sin((pitch * Math.PI) / 180) *
|
|
26
|
+
(map.metersPerPixel() ?? 0);
|
|
27
|
+
return [-back * Math.sin((bearing * Math.PI) / 180), -back * Math.cos((bearing * Math.PI) / 180), back];
|
|
28
|
+
};
|
|
29
|
+
/** What follows the camera as it moves: `send` called again once it has gone `RESEND_SHARE` of `radius` metres (or
|
|
30
|
+
* turned or zoomed as much), not at every frame of a drag */
|
|
31
|
+
export const followWhenMoved = (map, radius, send) => {
|
|
32
|
+
/** The view of the last call: center (metres), zoom, bearing, pitch */
|
|
33
|
+
let sent;
|
|
34
|
+
return () => {
|
|
35
|
+
const { center, zoom, bearing, pitch } = map.getCamera();
|
|
36
|
+
const [x, y] = [
|
|
37
|
+
center[0] * METRES_PER_DEGREE * Math.cos((center[1] * Math.PI) / 180),
|
|
38
|
+
center[1] * METRES_PER_DEGREE,
|
|
39
|
+
];
|
|
40
|
+
if (sent &&
|
|
41
|
+
Math.hypot(x - sent[0], y - sent[1]) < RESEND_SHARE * radius(zoom) &&
|
|
42
|
+
Math.abs(zoom - sent[2]) < RESEND_SHARE &&
|
|
43
|
+
Math.abs(bearing - sent[3]) < 45 * RESEND_SHARE &&
|
|
44
|
+
Math.abs(pitch - sent[4]) < 45 * RESEND_SHARE)
|
|
45
|
+
return;
|
|
46
|
+
sent = [x, y, zoom, bearing, pitch];
|
|
47
|
+
send();
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export const trees = (context, options = {}) => {
|
|
51
|
+
const { map } = context;
|
|
52
|
+
const { layers = isWoodland, spacing = treeSpacing, minZoom = STREET_ZOOM, maxTiles = 9, maxTrees = 30000, maxInstances = 25000, } = options;
|
|
53
|
+
const own = options.url !== undefined || options.data !== undefined;
|
|
54
|
+
const model = options.url ? { url: options.url } : { data: options.data ?? treeModel(options.colors) };
|
|
55
|
+
const before = options.before ? { before: options.before } : {};
|
|
56
|
+
const layer = map.addModels({ ...model, instances: [], ...before });
|
|
57
|
+
const add = (data) => map.addModels({ data, instances: [], ...before });
|
|
58
|
+
// The other kinds and the simplified trees far away on layers of their own, with it: conifers near, the broadleaved
|
|
59
|
+
// and the conifers far away (a model of the page's: every tree, in full)
|
|
60
|
+
const others = own
|
|
61
|
+
? undefined
|
|
62
|
+
: {
|
|
63
|
+
conifers: add(coniferModel(options.colors)),
|
|
64
|
+
farBroadleaved: add(treeModel(options.colors, true)),
|
|
65
|
+
farConifers: add(coniferModel(options.colors, true)),
|
|
66
|
+
};
|
|
67
|
+
if (others)
|
|
68
|
+
layer.companions.push(others.conifers, others.farBroadleaved, others.farConifers);
|
|
69
|
+
const renderer = context.renderer((l) => l.type === 'fill' && layers(l), []);
|
|
70
|
+
renderer.catch(() => undefined);
|
|
71
|
+
context.layers.push(layer);
|
|
72
|
+
/** The tiles held or asked for, by key, and the trees of those that came */
|
|
73
|
+
const requests = new TileRequests();
|
|
74
|
+
const found = new Map();
|
|
75
|
+
/** The trees drawn to the engine (longitude, latitude, altitude, heading, pitch, roll, scale each): all of them in
|
|
76
|
+
* full near the camera (as far as `TREES_NEAR_METRES` past the view's center), at most `maxInstances`; past `near`
|
|
77
|
+
* metres, simplified, those of a rank under
|
|
78
|
+
* `FAR_DENSITY` (near / distance)², at most `FAR_INSTANCES` times as many (a model of the page's: thinned as the
|
|
79
|
+
* full ones would be, none simplified) */
|
|
80
|
+
const send = () => {
|
|
81
|
+
const { center, zoom } = map.getCamera();
|
|
82
|
+
const cos = Math.cos((center[1] * Math.PI) / 180);
|
|
83
|
+
// The trees near the ground under the camera in full, as far as some way past the center
|
|
84
|
+
const [ex, ey, back] = groundUnderCamera(map);
|
|
85
|
+
const near = TREES_NEAR_METRES * 2 ** (16 - zoom) + back;
|
|
86
|
+
const density = others ? FAR_DENSITY : 1;
|
|
87
|
+
/** Each tree of the tiles that may be drawn: in full (near, or every one with a model of the page's) or
|
|
88
|
+
* simplified, with its score (the lowest kept first) */
|
|
89
|
+
const visit = (each) => {
|
|
90
|
+
found.forEach((t) => {
|
|
91
|
+
for (let i = 0; i < t.length / TREE_NUMBERS; i += 1) {
|
|
92
|
+
const dx = ((t[i * TREE_NUMBERS] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;
|
|
93
|
+
const dy = ((t[i * TREE_NUMBERS + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;
|
|
94
|
+
const distance = (dx * dx + dy * dy) / (near * near);
|
|
95
|
+
const rank = t[i * TREE_NUMBERS + 4] ?? 0;
|
|
96
|
+
if (distance <= 1)
|
|
97
|
+
each(t, i, true, rank);
|
|
98
|
+
else if (rank * (distance / density) < 1)
|
|
99
|
+
each(t, i, !others, rank * (distance / density));
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
// How many would be drawn: past a cap, the score kept lowered in proportion (the ranks are even, no sort needed)
|
|
104
|
+
let [fullCount, farCount] = [0, 0];
|
|
105
|
+
visit((_, __, full) => {
|
|
106
|
+
if (full)
|
|
107
|
+
fullCount += 1;
|
|
108
|
+
else
|
|
109
|
+
farCount += 1;
|
|
110
|
+
});
|
|
111
|
+
const limits = [
|
|
112
|
+
Math.min(1, maxInstances / Math.max(fullCount, 1)),
|
|
113
|
+
Math.min(1, (maxInstances * FAR_INSTANCES) / Math.max(farCount, 1)),
|
|
114
|
+
];
|
|
115
|
+
// The engine's numbers (longitude, latitude, altitude, heading, pitch, roll, scale): broadleaved and conifers in
|
|
116
|
+
// full, then simplified
|
|
117
|
+
const out = [[], [], [], []];
|
|
118
|
+
visit((t, i, full, score) => {
|
|
119
|
+
if (score >= (limits[full ? 0 : 1] ?? 1))
|
|
120
|
+
return;
|
|
121
|
+
const at = i * TREE_NUMBERS;
|
|
122
|
+
const conifer = others && t[at + 5] === 1 ? 1 : 0;
|
|
123
|
+
out[(full ? 0 : 2) + conifer]?.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);
|
|
124
|
+
});
|
|
125
|
+
const none = new Float64Array();
|
|
126
|
+
const [broadleaved = none, conifers = none, farBroadleaved = none, farConifers = none] = out.map((o) => Float64Array.from(o));
|
|
127
|
+
layer.setInstanceNumbers(broadleaved);
|
|
128
|
+
if (others) {
|
|
129
|
+
others.conifers.setInstanceNumbers(conifers);
|
|
130
|
+
others.farBroadleaved.setInstanceNumbers(farBroadleaved);
|
|
131
|
+
others.farConifers.setInstanceNumbers(farConifers);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const update = async () => {
|
|
135
|
+
if (context.destroyed())
|
|
136
|
+
return;
|
|
137
|
+
const { key, maxzoom, layers: list } = await renderer;
|
|
138
|
+
const camera = map.getCamera();
|
|
139
|
+
const z = maxzoom;
|
|
140
|
+
const wanted = camera.zoom < minZoom ? [] : tilesAround(map, camera, z, maxTiles);
|
|
141
|
+
const keys = new Set(wanted.map(([x, y]) => tileKey(z, x, y)));
|
|
142
|
+
const metres = list.map((l) => (typeof spacing === 'number' ? spacing : spacing(l)));
|
|
143
|
+
const dropped = requests.keys().filter((k) => !keys.has(k));
|
|
144
|
+
// Out of view: dropped, or no longer asked for
|
|
145
|
+
dropped.forEach((k) => {
|
|
146
|
+
requests.drop(k);
|
|
147
|
+
found.delete(k);
|
|
148
|
+
});
|
|
149
|
+
// Dense around the new center
|
|
150
|
+
send();
|
|
151
|
+
wanted.forEach(([x, y], index) => {
|
|
152
|
+
const k = tileKey(z, x, y);
|
|
153
|
+
if (requests.has(k))
|
|
154
|
+
return;
|
|
155
|
+
const work = {
|
|
156
|
+
type: 'trees',
|
|
157
|
+
key,
|
|
158
|
+
z,
|
|
159
|
+
x,
|
|
160
|
+
y,
|
|
161
|
+
spacing: metres,
|
|
162
|
+
maxTrees,
|
|
163
|
+
priority: nearPriority(index),
|
|
164
|
+
};
|
|
165
|
+
requests.ask(k, (signal) => context.request(z, x, y, work, signal), (r) => {
|
|
166
|
+
if (!('trees' in r))
|
|
167
|
+
return;
|
|
168
|
+
found.set(k, r.trees);
|
|
169
|
+
send();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
// While the camera moves, the trees drawn follow it (dense near it), chosen again once it has gone far enough
|
|
174
|
+
const follow = followWhenMoved(map, (zoom) => TREES_NEAR_METRES * 2 ** (16 - zoom), send);
|
|
175
|
+
context.followView(update, requests, follow);
|
|
176
|
+
return layer;
|
|
177
|
+
};
|
|
178
|
+
//# sourceMappingURL=trees.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trees.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/trees.ts"],"names":[],"mappings":"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","sourcesContent":["/** The trees of a vector basemap (`VectorTiles.trees`): 3D models scattered by the workers over its woods and grass */\n\nimport type { Layer, ModelLayer } from '../../layers/layers.ts';\nimport type { GeoMap } from '../../map.ts';\nimport type { BasemapWork } from '../../workers/basemap.worker.ts';\nimport { coniferModel, isWoodland, TREE_NUMBERS, type TreeColors, treeModel, treeSpacing } from '../trees.ts';\nimport type { StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { TileRequests } from './requests.ts';\nimport { nearPriority, STREET_ZOOM, tileKey, tilesAround } from './tiles.ts';\n\n/** Metres around the view's center where every tree is drawn in full at zoom 16 (twice as far a zoom level out);\n * past them, simplified (`treeModel(…, true)`) */\nconst TREES_NEAR_METRES = 350;\n\n/** The engine's vertical field of view (radians, `camera::FOV`): where the camera stands behind the view's center */\nconst FOV = 0.6435011087932844;\n\n/** How much denser the simplified trees far away stay than the full ones would (four times fewer triangles each): a\n * tree twice as far kept as often */\nconst FAR_DENSITY = 4;\n\n/** The simplified trees drawn at most, for so many full ones (`maxInstances`) */\nconst FAR_INSTANCES = 3;\n\n/** While the camera moves, the trees chosen again once it has gone this share of the full trees' radius (or turned\n * or zoomed as much): going through the tiles' trees at every frame of a drag would hold the main thread */\nconst RESEND_SHARE = 0.05;\n\n/** Metres in a degree of latitude (and of longitude at the equator), near enough for the trees' distances */\nexport const METRES_PER_DEGREE = 111320;\n\n/** The options of `VectorTiles.trees` */\nexport interface TreesOptions {\n layers?: (layer: StyleLayer) => boolean;\n spacing?: number | ((layer: StyleLayer) => number);\n minZoom?: number;\n maxTiles?: number;\n maxTrees?: number;\n maxInstances?: number;\n colors?: Partial<TreeColors>;\n url?: string;\n data?: ArrayBuffer | ArrayBufferView<ArrayBuffer>;\n before?: Layer;\n}\n\n/** The ground under the camera: east and north metres from the view's center, and its distance from it (the camera\n * stands behind the center of a tilted view, `FOV` its field of view) */\nexport const groundUnderCamera = (map: GeoMap): [east: number, north: number, distance: number] => {\n const { pitch, bearing } = map.getCamera();\n const back =\n ((0.5 * map.getCanvas().clientHeight) / Math.tan(FOV / 2)) *\n Math.sin((pitch * Math.PI) / 180) *\n (map.metersPerPixel() ?? 0);\n\n return [-back * Math.sin((bearing * Math.PI) / 180), -back * Math.cos((bearing * Math.PI) / 180), back];\n};\n\n/** What follows the camera as it moves: `send` called again once it has gone `RESEND_SHARE` of `radius` metres (or\n * turned or zoomed as much), not at every frame of a drag */\nexport const followWhenMoved = (map: GeoMap, radius: (zoom: number) => number, send: () => void): (() => void) => {\n /** The view of the last call: center (metres), zoom, bearing, pitch */\n let sent: [number, number, number, number, number] | undefined;\n\n return () => {\n const { center, zoom, bearing, pitch } = map.getCamera();\n const [x, y] = [\n center[0] * METRES_PER_DEGREE * Math.cos((center[1] * Math.PI) / 180),\n center[1] * METRES_PER_DEGREE,\n ];\n\n if (\n sent &&\n Math.hypot(x - sent[0], y - sent[1]) < RESEND_SHARE * radius(zoom) &&\n Math.abs(zoom - sent[2]) < RESEND_SHARE &&\n Math.abs(bearing - sent[3]) < 45 * RESEND_SHARE &&\n Math.abs(pitch - sent[4]) < 45 * RESEND_SHARE\n )\n return;\n sent = [x, y, zoom, bearing, pitch];\n send();\n };\n};\n\nexport const trees = (context: VectorTilesContext, options: TreesOptions = {}): ModelLayer => {\n const { map } = context;\n const {\n layers = isWoodland,\n spacing = treeSpacing,\n minZoom = STREET_ZOOM,\n maxTiles = 9,\n maxTrees = 30000,\n maxInstances = 25000,\n } = options;\n const own = options.url !== undefined || options.data !== undefined;\n const model = options.url ? { url: options.url } : { data: options.data ?? treeModel(options.colors) };\n const before = options.before ? { before: options.before } : {};\n const layer = map.addModels({ ...model, instances: [], ...before });\n const add = (data: Uint8Array<ArrayBuffer>) => map.addModels({ data, instances: [], ...before });\n // The other kinds and the simplified trees far away on layers of their own, with it: conifers near, the broadleaved\n // and the conifers far away (a model of the page's: every tree, in full)\n const others = own\n ? undefined\n : {\n conifers: add(coniferModel(options.colors)),\n farBroadleaved: add(treeModel(options.colors, true)),\n farConifers: add(coniferModel(options.colors, true)),\n };\n\n if (others) layer.companions.push(others.conifers, others.farBroadleaved, others.farConifers);\n const renderer = context.renderer((l) => l.type === 'fill' && layers(l), []);\n\n renderer.catch(() => undefined);\n context.layers.push(layer);\n\n /** The tiles held or asked for, by key, and the trees of those that came */\n const requests = new TileRequests();\n const found = new Map<string, Float64Array>();\n /** The trees drawn to the engine (longitude, latitude, altitude, heading, pitch, roll, scale each): all of them in\n * full near the camera (as far as `TREES_NEAR_METRES` past the view's center), at most `maxInstances`; past `near`\n * metres, simplified, those of a rank under\n * `FAR_DENSITY` (near / distance)², at most `FAR_INSTANCES` times as many (a model of the page's: thinned as the\n * full ones would be, none simplified) */\n const send = () => {\n const { center, zoom } = map.getCamera();\n const cos = Math.cos((center[1] * Math.PI) / 180);\n // The trees near the ground under the camera in full, as far as some way past the center\n const [ex, ey, back] = groundUnderCamera(map);\n const near = TREES_NEAR_METRES * 2 ** (16 - zoom) + back;\n const density = others ? FAR_DENSITY : 1;\n /** Each tree of the tiles that may be drawn: in full (near, or every one with a model of the page's) or\n * simplified, with its score (the lowest kept first) */\n const visit = (each: (t: Float64Array, i: number, full: boolean, score: number) => void) => {\n found.forEach((t) => {\n for (let i = 0; i < t.length / TREE_NUMBERS; i += 1) {\n const dx = ((t[i * TREE_NUMBERS] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;\n const dy = ((t[i * TREE_NUMBERS + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;\n const distance = (dx * dx + dy * dy) / (near * near);\n const rank = t[i * TREE_NUMBERS + 4] ?? 0;\n\n if (distance <= 1) each(t, i, true, rank);\n else if (rank * (distance / density) < 1) each(t, i, !others, rank * (distance / density));\n }\n });\n };\n // How many would be drawn: past a cap, the score kept lowered in proportion (the ranks are even, no sort needed)\n let [fullCount, farCount] = [0, 0];\n\n visit((_, __, full) => {\n if (full) fullCount += 1;\n else farCount += 1;\n });\n\n const limits = [\n Math.min(1, maxInstances / Math.max(fullCount, 1)),\n Math.min(1, (maxInstances * FAR_INSTANCES) / Math.max(farCount, 1)),\n ];\n // The engine's numbers (longitude, latitude, altitude, heading, pitch, roll, scale): broadleaved and conifers in\n // full, then simplified\n const out: number[][] = [[], [], [], []];\n\n visit((t, i, full, score) => {\n if (score >= (limits[full ? 0 : 1] ?? 1)) return;\n\n const at = i * TREE_NUMBERS;\n const conifer = others && t[at + 5] === 1 ? 1 : 0;\n\n out[(full ? 0 : 2) + conifer]?.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);\n });\n\n const none = new Float64Array();\n const [broadleaved = none, conifers = none, farBroadleaved = none, farConifers = none] = out.map((o) =>\n Float64Array.from(o),\n );\n\n layer.setInstanceNumbers(broadleaved);\n if (others) {\n others.conifers.setInstanceNumbers(conifers);\n others.farBroadleaved.setInstanceNumbers(farBroadleaved);\n others.farConifers.setInstanceNumbers(farConifers);\n }\n };\n const update = async () => {\n if (context.destroyed()) return;\n\n const { key, maxzoom, layers: list } = await renderer;\n const camera = map.getCamera();\n const z = maxzoom;\n const wanted = camera.zoom < minZoom ? [] : tilesAround(map, camera, z, maxTiles);\n const keys = new Set(wanted.map(([x, y]) => tileKey(z, x, y)));\n const metres = list.map((l) => (typeof spacing === 'number' ? spacing : spacing(l)));\n const dropped = requests.keys().filter((k) => !keys.has(k));\n\n // Out of view: dropped, or no longer asked for\n dropped.forEach((k) => {\n requests.drop(k);\n found.delete(k);\n });\n // Dense around the new center\n send();\n wanted.forEach(([x, y], index) => {\n const k = tileKey(z, x, y);\n\n if (requests.has(k)) return;\n\n const work: BasemapWork = {\n type: 'trees',\n key,\n z,\n x,\n y,\n spacing: metres,\n maxTrees,\n priority: nearPriority(index),\n };\n\n requests.ask(\n k,\n (signal) => context.request(z, x, y, work, signal),\n (r) => {\n if (!('trees' in r)) return;\n found.set(k, r.trees);\n send();\n },\n );\n });\n };\n // While the camera moves, the trees drawn follow it (dense near it), chosen again once it has gone far enough\n const follow = followWhenMoved(map, (zoom) => TREES_NEAR_METRES * 2 ** (16 - zoom), send);\n\n context.followView(update, requests, follow);\n\n return layer;\n};\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vector layer of a vector basemap (`VectorTiles.vectors`): its fills, lines and buildings cut by the workers
|
|
3
|
+
* into geometry the engine draws, the tiles following the view, and how its style layers are read for the engine.
|
|
4
|
+
*/
|
|
5
|
+
import type { Icons } from '../../layers/icons.ts';
|
|
6
|
+
import type { Layer } from '../../layers/layers.ts';
|
|
7
|
+
import type { VectorLayer } from '../../layers/vectors.ts';
|
|
8
|
+
import type { RoofMode } from '../../workers/basemap/geometry.ts';
|
|
9
|
+
import { type Json, type StyleLayer } from '../vectorstyle.ts';
|
|
10
|
+
import type { VectorTilesContext } from './context.ts';
|
|
11
|
+
/**
|
|
12
|
+
* A `line-dasharray` as the engine takes it: two dashes and gaps in line widths (an odd count repeated, as the
|
|
13
|
+
* canvas's `setLineDash`; past four, the first four), zeros for a solid line
|
|
14
|
+
*/
|
|
15
|
+
export declare const dashes: (value: Json | undefined, zoom: number) => [number, number, number, number];
|
|
16
|
+
/** Whether a style layer draws streets, which glow at night: its id names a road (OpenMapTiles' styles, PLAN IGN's),
|
|
17
|
+
* not its casing, a railway, a path or a tunnel */
|
|
18
|
+
export declare const isStreet: (layer: StyleLayer) => boolean;
|
|
19
|
+
/** A tile's styles with their patterns placed: each feature's pattern, as its index past one into `names` (float 28
|
|
20
|
+
* for a fill, 29 for a line or a building: floats the engine does not keep), replaced by its image's place in the icon
|
|
21
|
+
* atlas (texels) and pixel ratio, at 12 and 16 for a fill, 4 and 27 for a line or a building; none if the atlas has no
|
|
22
|
+
* such image; the atlas uploaded */
|
|
23
|
+
export declare const placePatterns: (styles: Float32Array, names: readonly string[] | undefined, icons: Icons, prefix: string) => Float32Array;
|
|
24
|
+
/** A `fill-translate` or `line-translate` at the camera's zoom (CSS pixels; none if it is not two numbers) */
|
|
25
|
+
export declare const translation: (value: Json | undefined, zoom: number) => [number, number];
|
|
26
|
+
/** The options of `VectorTiles.vectors` */
|
|
27
|
+
export interface VectorsOptions {
|
|
28
|
+
layers?: (layer: StyleLayer) => boolean;
|
|
29
|
+
streets?: (layer: StyleLayer) => boolean;
|
|
30
|
+
before?: Layer;
|
|
31
|
+
/** The buildings' roofs: from their data (`roof:shape`, `roof:height`; flat without, the default), generated from
|
|
32
|
+
* their outline where they have none (hipped, gabled or mansard by size and shape), or all flat */
|
|
33
|
+
roofs?: RoofMode;
|
|
34
|
+
/** The buildings' walls show their windows: glass by day, some lit at night (default false: only the lit ones) */
|
|
35
|
+
facades?: boolean;
|
|
36
|
+
}
|
|
37
|
+
export declare const vectors: (context: VectorTilesContext, options?: VectorsOptions) => VectorLayer;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vector layer of a vector basemap (`VectorTiles.vectors`): its fills, lines and buildings cut by the workers
|
|
3
|
+
* into geometry the engine draws, the tiles following the view, and how its style layers are read for the engine.
|
|
4
|
+
*/
|
|
5
|
+
import { FLOATS } from "../../layers/features.js";
|
|
6
|
+
import { evaluate, isExpression, vectorKind, zoomOnly } from "../vectorstyle.js";
|
|
7
|
+
import { TileRequests } from "./requests.js";
|
|
8
|
+
import { nearPriority, parseTileKey, tileKey, tileTriples } from "./tiles.js";
|
|
9
|
+
/** The deepest level `vectors()` cuts its tiles at: past the source's deepest level, its tiles cut again into deeper
|
|
10
|
+
* ones (overzoom, as MapLibre does) down to level 18, their styles those of their level, smaller tiles
|
|
11
|
+
* drawn in a closer view; past it, the tiles of that level stretched */
|
|
12
|
+
const OVERZOOM_LEVEL = 18;
|
|
13
|
+
/** The deepest level of the tiles of `vectors()` over a source whose deepest is `maxzoom` */
|
|
14
|
+
const deepestLevel = (maxzoom) => Math.max(maxzoom, OVERZOOM_LEVEL);
|
|
15
|
+
/**
|
|
16
|
+
* A `line-dasharray` as the engine takes it: two dashes and gaps in line widths (an odd count repeated, as the
|
|
17
|
+
* canvas's `setLineDash`; past four, the first four), zeros for a solid line
|
|
18
|
+
*/
|
|
19
|
+
export const dashes = (value, zoom) => {
|
|
20
|
+
const v = isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : value;
|
|
21
|
+
const list = Array.isArray(v) ? v.map(Number).filter((d) => Number.isFinite(d) && d >= 0) : [];
|
|
22
|
+
const even = list.length % 2 === 1 ? [...list, ...list] : list;
|
|
23
|
+
const [a = 0, b = 0, c = 0, d = 0] = even.length >= 2 && even.some((x) => x > 0) ? even : [];
|
|
24
|
+
return [a, b, c, d];
|
|
25
|
+
};
|
|
26
|
+
/** Whether a style layer draws streets, which glow at night: its id names a road (OpenMapTiles' styles, PLAN IGN's),
|
|
27
|
+
* not its casing, a railway, a path or a tunnel */
|
|
28
|
+
export const isStreet = (layer) => /road|highway|street|motorway|trunk|primary|secondary|tertiary|minor|routier/i.test(layer.id) &&
|
|
29
|
+
!/casing|outline|rail|path|track|ferry|tunnel|pier|area|pattern|label/i.test(layer.id);
|
|
30
|
+
/** A `line-cap` as the engine draws it, at the camera's zoom (MapLibre's default: butt) */
|
|
31
|
+
const lineCap = (value, zoom) => {
|
|
32
|
+
const v = isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : value;
|
|
33
|
+
return v === 'round' || v === 'square' ? v : 'butt';
|
|
34
|
+
};
|
|
35
|
+
/** A `line-join` as the engine draws it, at the camera's zoom (MapLibre's default: miter) */
|
|
36
|
+
const lineJoin = (value, zoom) => {
|
|
37
|
+
const v = isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : value;
|
|
38
|
+
return v === 'round' || v === 'bevel' ? v : 'miter';
|
|
39
|
+
};
|
|
40
|
+
/** A `line-miter-limit` at the camera's zoom (MapLibre's default: 2) */
|
|
41
|
+
const miterLimit = (value, zoom) => {
|
|
42
|
+
const v = Number(isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : (value ?? 2));
|
|
43
|
+
return Number.isFinite(v) ? v : 2;
|
|
44
|
+
};
|
|
45
|
+
/** A tile's styles with their patterns placed: each feature's pattern, as its index past one into `names` (float 28
|
|
46
|
+
* for a fill, 29 for a line or a building: floats the engine does not keep), replaced by its image's place in the icon
|
|
47
|
+
* atlas (texels) and pixel ratio, at 12 and 16 for a fill, 4 and 27 for a line or a building; none if the atlas has no
|
|
48
|
+
* such image; the atlas uploaded */
|
|
49
|
+
export const placePatterns = (styles, names, icons, prefix) => {
|
|
50
|
+
if (!names?.length)
|
|
51
|
+
return styles;
|
|
52
|
+
// Thousands of features a tile: a loop
|
|
53
|
+
for (let f = 0; f + FLOATS <= styles.length; f += FLOATS) {
|
|
54
|
+
const fill = styles[f + 28] ?? 0;
|
|
55
|
+
const line = styles[f + 29] ?? 0;
|
|
56
|
+
const index = fill > 0 ? fill : line;
|
|
57
|
+
if (index <= 0)
|
|
58
|
+
continue;
|
|
59
|
+
const icon = icons.get(prefix + (names[index - 1] ?? ''));
|
|
60
|
+
const place = icon ? [icon.x, icon.y, icon.width, icon.height] : [0, 0, 0, 0];
|
|
61
|
+
const ratio = icon?.pixelRatio ?? 0;
|
|
62
|
+
if (fill > 0)
|
|
63
|
+
styles.set([...place, ratio], f + 12);
|
|
64
|
+
else {
|
|
65
|
+
styles.set(place, f + 4);
|
|
66
|
+
styles[f + 27] = ratio;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
icons.flush();
|
|
70
|
+
return styles;
|
|
71
|
+
};
|
|
72
|
+
/** The paint properties of the patterns `vectors()` draws, whose images come from the style's sprite */
|
|
73
|
+
const PATTERNS = ['fill-pattern', 'background-pattern', 'line-pattern', 'fill-extrusion-pattern'];
|
|
74
|
+
/** A `fill-translate` or `line-translate` at the camera's zoom (CSS pixels; none if it is not two numbers) */
|
|
75
|
+
export const translation = (value, zoom) => {
|
|
76
|
+
const v = isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : value;
|
|
77
|
+
const [x, y] = Array.isArray(v) ? v.map(Number) : [];
|
|
78
|
+
return Number.isFinite(x) && Number.isFinite(y) ? [x ?? 0, y ?? 0] : [0, 0];
|
|
79
|
+
};
|
|
80
|
+
export const vectors = (context, options = {}) => {
|
|
81
|
+
const { map } = context;
|
|
82
|
+
const { layers = () => true, streets = isStreet, before, roofs = 'data', facades = false } = options;
|
|
83
|
+
const vector = map.addVectorLayer(before);
|
|
84
|
+
vector.setFacades(facades);
|
|
85
|
+
const state = { renderer: context.renderer((l) => vectorKind(l) !== undefined && layers(l), []), update: 0, style: 0 };
|
|
86
|
+
state.renderer.catch(() => undefined);
|
|
87
|
+
/** The style's sprites among the map's icons, if a layer drawn has a pattern: waited for before the first tiles */
|
|
88
|
+
const sprites = context.ready
|
|
89
|
+
.then(({ style }) => style.layers.some((l) => layers(l) && PATTERNS.some((k) => l.paint?.[k] !== undefined))
|
|
90
|
+
? context.addSprites()
|
|
91
|
+
: undefined)
|
|
92
|
+
.catch(() => undefined);
|
|
93
|
+
const placed = (styles, names) => placePatterns(styles, names, map.icons, context.iconPrefix);
|
|
94
|
+
context.layers.push(vector);
|
|
95
|
+
const sublayers = (list) => {
|
|
96
|
+
const zoom = map.getCamera().zoom;
|
|
97
|
+
return list.map((l) => ({
|
|
98
|
+
id: l.id,
|
|
99
|
+
sourceLayer: l['source-layer'],
|
|
100
|
+
kind: vectorKind(l) ?? 'fill',
|
|
101
|
+
minZoom: l.minzoom ?? 0,
|
|
102
|
+
maxZoom: l.maxzoom ?? 24,
|
|
103
|
+
visible: l.layout?.visibility !== 'none',
|
|
104
|
+
opacity: zoomOnly(l.paint?.[`${l.type}-opacity`], 1) ?? 1,
|
|
105
|
+
cap: lineCap(l.layout?.['line-cap'], zoom),
|
|
106
|
+
join: lineJoin(l.layout?.['line-join'], zoom),
|
|
107
|
+
miterLimit: miterLimit(l.layout?.['line-miter-limit'], zoom),
|
|
108
|
+
translate: translation(l.paint?.[`${l.type}-translate`], zoom),
|
|
109
|
+
translateAnchor: l.paint?.[`${l.type}-translate-anchor`] === 'viewport' ? 'viewport' : 'map',
|
|
110
|
+
patterned: l.paint?.['fill-pattern'] !== undefined || l.paint?.['background-pattern'] !== undefined,
|
|
111
|
+
lit: l.type === 'line' && streets(l),
|
|
112
|
+
dash: l.type === 'line' ? dashes(l.paint?.['line-dasharray'], zoom) : [0, 0, 0, 0],
|
|
113
|
+
}));
|
|
114
|
+
};
|
|
115
|
+
/** The tiles held or asked for, by `z/x/y` */
|
|
116
|
+
const requests = new TileRequests();
|
|
117
|
+
/** A tile's geometry, or its styles alone, asked of the worker of its tile of the source's level (which keeps the
|
|
118
|
+
* decoded tile its deeper tiles are cut from) */
|
|
119
|
+
const ask = ({ key, maxzoom }, [z, x, y], styles, priority, signal) => {
|
|
120
|
+
const d = Math.max(0, z - maxzoom);
|
|
121
|
+
const work = { type: 'vectors', key, z, x, y, deepest: deepestLevel(maxzoom), roofs, priority };
|
|
122
|
+
// The geometry made ready for the GPU in the workers, with the prisms the relief needs
|
|
123
|
+
return context.request(z - d, Math.floor(x / 2 ** d), Math.floor(y / 2 ** d), styles ? { ...work, styles } : { ...work, prism: map.hasRelief }, signal);
|
|
124
|
+
};
|
|
125
|
+
// The workers tessellate the tiles (the main thread only uploads them), once they know the module
|
|
126
|
+
context.broadcast({ type: 'tess', url: map.tessUrl });
|
|
127
|
+
/** Asks the workers again for the styles of a tile held, under the current style; the tile's geometry stays as it
|
|
128
|
+
* is */
|
|
129
|
+
const restyleTile = async (renderer, k) => {
|
|
130
|
+
const r = await ask(renderer, parseTileKey(k), true, 'auto').catch(() => undefined);
|
|
131
|
+
if (r && 'styles' in r)
|
|
132
|
+
vector.setTileStyles(k, placed(r.styles, r.patterns));
|
|
133
|
+
};
|
|
134
|
+
const update = async () => {
|
|
135
|
+
if (context.destroyed())
|
|
136
|
+
return;
|
|
137
|
+
const generation = ++state.update;
|
|
138
|
+
// The style the tiles are cut under: that of the renderer awaited, a restyle meanwhile (a paint property set as the
|
|
139
|
+
// style loads) asking their styles again once they are there
|
|
140
|
+
const style = state.style;
|
|
141
|
+
const { key, maxzoom, layers: list } = await state.renderer;
|
|
142
|
+
await sprites;
|
|
143
|
+
vector.setSublayers(sublayers(state.own ?? list));
|
|
144
|
+
const wanted = tileTriples(map.engine.vectorTilesInView(0, deepestLevel(maxzoom)));
|
|
145
|
+
const keys = new Set(wanted.map((t) => tileKey(...t)));
|
|
146
|
+
const loads = wanted.flatMap((t, index) => {
|
|
147
|
+
const k = tileKey(...t);
|
|
148
|
+
if (requests.has(k))
|
|
149
|
+
return [];
|
|
150
|
+
return [
|
|
151
|
+
requests.ask(k, (signal) => ask({ key, maxzoom }, t, false, nearPriority(index, 'high', 'auto'), signal), async (r) => {
|
|
152
|
+
if (!('vectors' in r))
|
|
153
|
+
return;
|
|
154
|
+
await vector.setTile(k, { ...r.vectors, styles: placed(r.vectors.styles, r.vectors.patterns) });
|
|
155
|
+
// Cut under a style changed since: its styles asked for again
|
|
156
|
+
if (style !== state.style)
|
|
157
|
+
await restyleTile(await state.renderer, k);
|
|
158
|
+
}),
|
|
159
|
+
];
|
|
160
|
+
});
|
|
161
|
+
// Out of view: those still asked for go at once, those drawn once their replacements are there (no hole). The
|
|
162
|
+
// drawn ones are those the engine shows, held or not (a recut forgets what it held, not what is drawn)
|
|
163
|
+
const drop = (drawn) => {
|
|
164
|
+
const shown = new Set(vector.tileKeys);
|
|
165
|
+
const known = new Set([...requests.keys(), ...(drawn ? shown : [])]);
|
|
166
|
+
known.forEach((k) => {
|
|
167
|
+
if (keys.has(k) || shown.has(k) !== drawn)
|
|
168
|
+
return;
|
|
169
|
+
requests.drop(k);
|
|
170
|
+
vector.removeTile(k);
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
drop(false);
|
|
174
|
+
// Every tile of the view, those an earlier update asked for too: a tile out of view stays drawn until all of them
|
|
175
|
+
// are there
|
|
176
|
+
await Promise.all([...loads, requests.answered(keys)]);
|
|
177
|
+
// A later update (the view moved again meanwhile) drops for its own view: these keys are no longer the view
|
|
178
|
+
if (!context.destroyed() && generation === state.update)
|
|
179
|
+
drop(true);
|
|
180
|
+
};
|
|
181
|
+
const refresh = () => {
|
|
182
|
+
update().catch(() => undefined);
|
|
183
|
+
};
|
|
184
|
+
/** The style layers changed: the workers' copy, then the styles of the tiles held */
|
|
185
|
+
const restyle = async (list) => {
|
|
186
|
+
state.own = list;
|
|
187
|
+
state.style++;
|
|
188
|
+
state.renderer = state.renderer.then(({ key }) => context.renderer(() => false, list, key));
|
|
189
|
+
const renderer = await state.renderer;
|
|
190
|
+
vector.setSublayers(sublayers(list));
|
|
191
|
+
await Promise.all(vector.tileKeys.map((k) => restyleTile(renderer, k)));
|
|
192
|
+
};
|
|
193
|
+
vector.restyle = (id, group, name, value) => {
|
|
194
|
+
state.renderer
|
|
195
|
+
.then(({ layers: list }) => {
|
|
196
|
+
const next = (state.own ?? list).map((l) => l.id === id ? { ...l, [group]: { ...l[group], [name]: value } } : l);
|
|
197
|
+
// Visibility and dashes are the engine's: the tiles stay as they are
|
|
198
|
+
if ((group === 'layout' && name === 'visibility') || name === 'line-dasharray') {
|
|
199
|
+
state.own = next;
|
|
200
|
+
vector.setSublayers(sublayers(next));
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
// An outline added or taken away: a feature more or less in each tile, cut again
|
|
204
|
+
if (name === 'fill-outline-color' || name === 'fill-antialias') {
|
|
205
|
+
state.own = next;
|
|
206
|
+
state.style++;
|
|
207
|
+
state.renderer = state.renderer.then(({ key }) => context.renderer(() => false, next, key));
|
|
208
|
+
vector.setSublayers(sublayers(next));
|
|
209
|
+
vector.recut?.();
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
return restyle(next);
|
|
213
|
+
})
|
|
214
|
+
.catch(() => undefined);
|
|
215
|
+
};
|
|
216
|
+
vector.recut = () => {
|
|
217
|
+
requests.abortAll();
|
|
218
|
+
refresh();
|
|
219
|
+
};
|
|
220
|
+
vector.styled = state.renderer.then(({ layers: list }) => {
|
|
221
|
+
if (!context.destroyed())
|
|
222
|
+
vector.setSublayers(sublayers(state.own ?? list));
|
|
223
|
+
});
|
|
224
|
+
// Reported by the style's `ready`
|
|
225
|
+
vector.styled.catch(() => undefined);
|
|
226
|
+
// While the camera moves, the tiles follow it (as the labels do: a long drag or flight does not leave the view of
|
|
227
|
+
// its start drawn)
|
|
228
|
+
context.followView(update, requests, update);
|
|
229
|
+
return vector;
|
|
230
|
+
};
|
|
231
|
+
//# sourceMappingURL=vectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectors.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/vectors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The vector layer of a vector basemap (`VectorTiles.vectors`): its fills, lines and buildings cut by the workers\n * into geometry the engine draws, the tiles following the view, and how its style layers are read for the engine.\n */\n\nimport { FLOATS } from '../../layers/features.ts';\nimport type { Icons } from '../../layers/icons.ts';\nimport type { Layer } from '../../layers/layers.ts';\nimport type { VectorLayer, VectorSublayer } from '../../layers/vectors.ts';\nimport type { RoofMode } from '../../workers/basemap/geometry.ts';\nimport type { BasemapWork, Priority } from '../../workers/basemap.worker.ts';\nimport { evaluate, isExpression, type Json, type StyleLayer, vectorKind, zoomOnly } from '../vectorstyle.ts';\nimport type { Renderer, VectorTilesContext } from './context.ts';\nimport { TileRequests } from './requests.ts';\nimport { nearPriority, parseTileKey, type TileTriple, tileKey, tileTriples } from './tiles.ts';\n\n/** The deepest level `vectors()` cuts its tiles at: past the source's deepest level, its tiles cut again into deeper\n * ones (overzoom, as MapLibre does) down to level 18, their styles those of their level, smaller tiles\n * drawn in a closer view; past it, the tiles of that level stretched */\nconst OVERZOOM_LEVEL = 18;\n\n/** The deepest level of the tiles of `vectors()` over a source whose deepest is `maxzoom` */\nconst deepestLevel = (maxzoom: number): number => Math.max(maxzoom, OVERZOOM_LEVEL);\n\n/**\n * A `line-dasharray` as the engine takes it: two dashes and gaps in line widths (an odd count repeated, as the\n * canvas's `setLineDash`; past four, the first four), zeros for a solid line\n */\nexport const dashes = (value: Json | undefined, zoom: number): [number, number, number, number] => {\n const v = isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : value;\n const list = Array.isArray(v) ? v.map(Number).filter((d) => Number.isFinite(d) && d >= 0) : [];\n const even = list.length % 2 === 1 ? [...list, ...list] : list;\n const [a = 0, b = 0, c = 0, d = 0] = even.length >= 2 && even.some((x) => x > 0) ? even : [];\n\n return [a, b, c, d];\n};\n\n/** Whether a style layer draws streets, which glow at night: its id names a road (OpenMapTiles' styles, PLAN IGN's),\n * not its casing, a railway, a path or a tunnel */\nexport const isStreet = (layer: StyleLayer): boolean =>\n /road|highway|street|motorway|trunk|primary|secondary|tertiary|minor|routier/i.test(layer.id) &&\n !/casing|outline|rail|path|track|ferry|tunnel|pier|area|pattern|label/i.test(layer.id);\n\n/** A `line-cap` as the engine draws it, at the camera's zoom (MapLibre's default: butt) */\nconst lineCap = (value: Json | undefined, zoom: number): 'butt' | 'round' | 'square' => {\n const v = isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : value;\n\n return v === 'round' || v === 'square' ? v : 'butt';\n};\n\n/** A `line-join` as the engine draws it, at the camera's zoom (MapLibre's default: miter) */\nconst lineJoin = (value: Json | undefined, zoom: number): 'miter' | 'bevel' | 'round' => {\n const v = isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : value;\n\n return v === 'round' || v === 'bevel' ? v : 'miter';\n};\n\n/** A `line-miter-limit` at the camera's zoom (MapLibre's default: 2) */\nconst miterLimit = (value: Json | undefined, zoom: number): number => {\n const v = Number(isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : (value ?? 2));\n\n return Number.isFinite(v) ? v : 2;\n};\n\n/** A tile's styles with their patterns placed: each feature's pattern, as its index past one into `names` (float 28\n * for a fill, 29 for a line or a building: floats the engine does not keep), replaced by its image's place in the icon\n * atlas (texels) and pixel ratio, at 12 and 16 for a fill, 4 and 27 for a line or a building; none if the atlas has no\n * such image; the atlas uploaded */\nexport const placePatterns = (\n styles: Float32Array,\n names: readonly string[] | undefined,\n icons: Icons,\n prefix: string,\n): Float32Array => {\n if (!names?.length) return styles;\n // Thousands of features a tile: a loop\n for (let f = 0; f + FLOATS <= styles.length; f += FLOATS) {\n const fill = styles[f + 28] ?? 0;\n const line = styles[f + 29] ?? 0;\n const index = fill > 0 ? fill : line;\n\n if (index <= 0) continue;\n\n const icon = icons.get(prefix + (names[index - 1] ?? ''));\n const place = icon ? [icon.x, icon.y, icon.width, icon.height] : [0, 0, 0, 0];\n const ratio = icon?.pixelRatio ?? 0;\n\n if (fill > 0) styles.set([...place, ratio], f + 12);\n else {\n styles.set(place, f + 4);\n styles[f + 27] = ratio;\n }\n }\n icons.flush();\n\n return styles;\n};\n\n/** The paint properties of the patterns `vectors()` draws, whose images come from the style's sprite */\nconst PATTERNS = ['fill-pattern', 'background-pattern', 'line-pattern', 'fill-extrusion-pattern'];\n\n/** A `fill-translate` or `line-translate` at the camera's zoom (CSS pixels; none if it is not two numbers) */\nexport const translation = (value: Json | undefined, zoom: number): [number, number] => {\n const v = isExpression(value) ? evaluate(value, { zoom, properties: {}, type: 'Unknown' }) : value;\n const [x, y] = Array.isArray(v) ? v.map(Number) : [];\n\n return Number.isFinite(x) && Number.isFinite(y) ? [x ?? 0, y ?? 0] : [0, 0];\n};\n\n/** The options of `VectorTiles.vectors` */\nexport interface VectorsOptions {\n layers?: (layer: StyleLayer) => boolean;\n streets?: (layer: StyleLayer) => boolean;\n before?: Layer;\n /** The buildings' roofs: from their data (`roof:shape`, `roof:height`; flat without, the default), generated from\n * their outline where they have none (hipped, gabled or mansard by size and shape), or all flat */\n roofs?: RoofMode;\n /** The buildings' walls show their windows: glass by day, some lit at night (default false: only the lit ones) */\n facades?: boolean;\n}\n\nexport const vectors = (context: VectorTilesContext, options: VectorsOptions = {}): VectorLayer => {\n const { map } = context;\n const { layers = () => true, streets = isStreet, before, roofs = 'data', facades = false } = options;\n const vector = map.addVectorLayer(before);\n\n vector.setFacades(facades);\n const state: {\n renderer: Promise<Renderer>;\n /** The style layers as the application changed them (`setPaintProperty`…): a copy, its style left as it is */\n own?: StyleLayer[];\n /** Bumped by each update: only the last one drops the tiles out of its view */\n update: number;\n /** Bumped by each restyle: a tile cut under an older style is restyled once it is there */\n style: number;\n } = { renderer: context.renderer((l) => vectorKind(l) !== undefined && layers(l), []), update: 0, style: 0 };\n\n state.renderer.catch(() => undefined);\n\n /** The style's sprites among the map's icons, if a layer drawn has a pattern: waited for before the first tiles */\n const sprites = context.ready\n .then(({ style }) =>\n style.layers.some((l) => layers(l) && PATTERNS.some((k) => l.paint?.[k] !== undefined))\n ? context.addSprites()\n : undefined,\n )\n .catch(() => undefined);\n const placed = (styles: Float32Array, names: readonly string[] | undefined) =>\n placePatterns(styles, names, map.icons, context.iconPrefix);\n context.layers.push(vector);\n\n const sublayers = (list: StyleLayer[]): VectorSublayer[] => {\n const zoom = map.getCamera().zoom;\n\n return list.map((l) => ({\n id: l.id,\n sourceLayer: l['source-layer'],\n kind: vectorKind(l) ?? 'fill',\n minZoom: l.minzoom ?? 0,\n maxZoom: l.maxzoom ?? 24,\n visible: l.layout?.visibility !== 'none',\n opacity: zoomOnly(l.paint?.[`${l.type}-opacity`], 1) ?? 1,\n cap: lineCap(l.layout?.['line-cap'], zoom),\n join: lineJoin(l.layout?.['line-join'], zoom),\n miterLimit: miterLimit(l.layout?.['line-miter-limit'], zoom),\n translate: translation(l.paint?.[`${l.type}-translate`], zoom),\n translateAnchor: l.paint?.[`${l.type}-translate-anchor`] === 'viewport' ? 'viewport' : 'map',\n patterned: l.paint?.['fill-pattern'] !== undefined || l.paint?.['background-pattern'] !== undefined,\n lit: l.type === 'line' && streets(l),\n dash: l.type === 'line' ? dashes(l.paint?.['line-dasharray'], zoom) : [0, 0, 0, 0],\n }));\n };\n\n /** The tiles held or asked for, by `z/x/y` */\n const requests = new TileRequests();\n /** A tile's geometry, or its styles alone, asked of the worker of its tile of the source's level (which keeps the\n * decoded tile its deeper tiles are cut from) */\n const ask = (\n { key, maxzoom }: { key: string; maxzoom: number },\n [z, x, y]: TileTriple,\n styles: boolean,\n priority: Priority,\n signal?: AbortSignal,\n ) => {\n const d = Math.max(0, z - maxzoom);\n const work: BasemapWork = { type: 'vectors', key, z, x, y, deepest: deepestLevel(maxzoom), roofs, priority };\n\n // The geometry made ready for the GPU in the workers, with the prisms the relief needs\n return context.request(\n z - d,\n Math.floor(x / 2 ** d),\n Math.floor(y / 2 ** d),\n styles ? { ...work, styles } : { ...work, prism: map.hasRelief },\n signal,\n );\n };\n\n // The workers tessellate the tiles (the main thread only uploads them), once they know the module\n context.broadcast({ type: 'tess', url: map.tessUrl });\n /** Asks the workers again for the styles of a tile held, under the current style; the tile's geometry stays as it\n * is */\n const restyleTile = async (renderer: { key: string; maxzoom: number }, k: string) => {\n const r = await ask(renderer, parseTileKey(k), true, 'auto').catch(() => undefined);\n\n if (r && 'styles' in r) vector.setTileStyles(k, placed(r.styles, r.patterns));\n };\n const update = async () => {\n if (context.destroyed()) return;\n\n const generation = ++state.update;\n // The style the tiles are cut under: that of the renderer awaited, a restyle meanwhile (a paint property set as the\n // style loads) asking their styles again once they are there\n const style = state.style;\n const { key, maxzoom, layers: list } = await state.renderer;\n\n await sprites;\n\n vector.setSublayers(sublayers(state.own ?? list));\n\n const wanted = tileTriples(map.engine.vectorTilesInView(0, deepestLevel(maxzoom)));\n const keys = new Set(wanted.map((t) => tileKey(...t)));\n const loads = wanted.flatMap((t, index) => {\n const k = tileKey(...t);\n\n if (requests.has(k)) return [];\n\n return [\n requests.ask(\n k,\n (signal) => ask({ key, maxzoom }, t, false, nearPriority(index, 'high', 'auto'), signal),\n async (r) => {\n if (!('vectors' in r)) return;\n await vector.setTile(k, { ...r.vectors, styles: placed(r.vectors.styles, r.vectors.patterns) });\n // Cut under a style changed since: its styles asked for again\n if (style !== state.style) await restyleTile(await state.renderer, k);\n },\n ),\n ];\n });\n // Out of view: those still asked for go at once, those drawn once their replacements are there (no hole). The\n // drawn ones are those the engine shows, held or not (a recut forgets what it held, not what is drawn)\n const drop = (drawn: boolean) => {\n const shown = new Set(vector.tileKeys);\n const known = new Set([...requests.keys(), ...(drawn ? shown : [])]);\n\n known.forEach((k) => {\n if (keys.has(k) || shown.has(k) !== drawn) return;\n requests.drop(k);\n vector.removeTile(k);\n });\n };\n\n drop(false);\n // Every tile of the view, those an earlier update asked for too: a tile out of view stays drawn until all of them\n // are there\n await Promise.all([...loads, requests.answered(keys)]);\n // A later update (the view moved again meanwhile) drops for its own view: these keys are no longer the view\n if (!context.destroyed() && generation === state.update) drop(true);\n };\n const refresh = () => {\n update().catch(() => undefined);\n };\n /** The style layers changed: the workers' copy, then the styles of the tiles held */\n const restyle = async (list: StyleLayer[]) => {\n state.own = list;\n state.style++;\n state.renderer = state.renderer.then(({ key }) => context.renderer(() => false, list, key));\n\n const renderer = await state.renderer;\n\n vector.setSublayers(sublayers(list));\n await Promise.all(vector.tileKeys.map((k) => restyleTile(renderer, k)));\n };\n\n vector.restyle = (id, group, name, value) => {\n state.renderer\n .then(({ layers: list }) => {\n const next = (state.own ?? list).map((l) =>\n l.id === id ? { ...l, [group]: { ...l[group], [name]: value } } : l,\n );\n\n // Visibility and dashes are the engine's: the tiles stay as they are\n if ((group === 'layout' && name === 'visibility') || name === 'line-dasharray') {\n state.own = next;\n vector.setSublayers(sublayers(next));\n\n return undefined;\n }\n // An outline added or taken away: a feature more or less in each tile, cut again\n if (name === 'fill-outline-color' || name === 'fill-antialias') {\n state.own = next;\n state.style++;\n state.renderer = state.renderer.then(({ key }) => context.renderer(() => false, next, key));\n vector.setSublayers(sublayers(next));\n vector.recut?.();\n\n return undefined;\n }\n\n return restyle(next);\n })\n .catch(() => undefined);\n };\n vector.recut = () => {\n requests.abortAll();\n refresh();\n };\n vector.styled = state.renderer.then(({ layers: list }) => {\n if (!context.destroyed()) vector.setSublayers(sublayers(state.own ?? list));\n });\n // Reported by the style's `ready`\n vector.styled.catch(() => undefined);\n\n // While the camera moves, the tiles follow it (as the labels do: a long drag or flight does not leave the view of\n // its start drawn)\n context.followView(update, requests, update);\n\n return vector;\n};\n"]}
|