isard 1.6.0 → 1.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/CHANGELOG.md +70 -0
- package/dist/basemap/furniture.d.ts +20 -2
- package/dist/basemap/furniture.js +72 -3
- package/dist/basemap/furniture.js.map +1 -1
- package/dist/basemap/meshes.d.ts +21 -0
- package/dist/basemap/meshes.js +159 -0
- package/dist/basemap/meshes.js.map +1 -0
- package/dist/basemap/placed.d.ts +13 -0
- package/dist/basemap/placed.js +14 -0
- package/dist/basemap/placed.js.map +1 -0
- package/dist/basemap/trees.d.ts +4 -14
- package/dist/basemap/trees.js +12 -93
- package/dist/basemap/trees.js.map +1 -1
- package/dist/basemap/vectortiles/context.d.ts +4 -2
- package/dist/basemap/vectortiles/context.js.map +1 -1
- package/dist/basemap/vectortiles/extrusions.d.ts +1 -1
- package/dist/basemap/vectortiles/extrusions.js +7 -16
- package/dist/basemap/vectortiles/extrusions.js.map +1 -1
- package/dist/basemap/vectortiles/furniture.d.ts +19 -0
- package/dist/basemap/vectortiles/furniture.js +29 -0
- package/dist/basemap/vectortiles/furniture.js.map +1 -0
- package/dist/basemap/vectortiles/labels.js +8 -1
- package/dist/basemap/vectortiles/labels.js.map +1 -1
- package/dist/basemap/vectortiles/lamps.js +11 -76
- package/dist/basemap/vectortiles/lamps.js.map +1 -1
- package/dist/basemap/vectortiles/placed.d.ts +38 -0
- package/dist/basemap/vectortiles/placed.js +143 -0
- package/dist/basemap/vectortiles/placed.js.map +1 -0
- package/dist/basemap/vectortiles/street-wind.js +4 -6
- package/dist/basemap/vectortiles/street-wind.js.map +1 -1
- package/dist/basemap/vectortiles/trees.d.ts +2 -9
- package/dist/basemap/vectortiles/trees.js +34 -165
- package/dist/basemap/vectortiles/trees.js.map +1 -1
- package/dist/basemap/vectortiles/vectors.d.ts +4 -5
- package/dist/basemap/vectortiles/vectors.js +17 -16
- package/dist/basemap/vectortiles/vectors.js.map +1 -1
- package/dist/basemap/vectortiles.d.ts +14 -4
- package/dist/basemap/vectortiles.js +40 -12
- package/dist/basemap/vectortiles.js.map +1 -1
- package/dist/basemap/wmts.js +2 -2
- package/dist/basemap/wmts.js.map +1 -1
- package/dist/basemap.worker.js +2 -2
- package/dist/basemap.worker.js.map +18 -14
- package/dist/bind/layers.d.ts +10 -3
- package/dist/bind/layers.js +11 -4
- package/dist/bind/layers.js.map +1 -1
- package/dist/data/collada.js +3 -17
- package/dist/data/collada.js.map +1 -1
- package/dist/data/crs.js +1 -1
- package/dist/data/crs.js.map +1 -1
- package/dist/data/ifc.js +21 -22
- package/dist/data/ifc.js.map +1 -1
- package/dist/geoplateforme.d.ts +16 -4
- package/dist/geoplateforme.js +26 -4
- package/dist/geoplateforme.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -3
- 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.js +5 -4
- package/dist/layers/extrusions.js.map +1 -1
- package/dist/layers/features.d.ts +0 -2
- package/dist/layers/features.js +5 -6
- package/dist/layers/features.js.map +1 -1
- package/dist/layers/layers.d.ts +2 -0
- package/dist/layers/layers.js +11 -0
- package/dist/layers/layers.js.map +1 -1
- package/dist/layers/panoramas.d.ts +32 -10
- package/dist/layers/panoramas.js +55 -28
- package/dist/layers/panoramas.js.map +1 -1
- package/dist/layers/photos.js +5 -6
- package/dist/layers/photos.js.map +1 -1
- package/dist/layers/trees.js +7 -7
- package/dist/layers/trees.js.map +1 -1
- package/dist/layers/vectors.d.ts +1 -0
- package/dist/layers/vectors.js +23 -8
- package/dist/layers/vectors.js.map +1 -1
- package/dist/map/frame-loop.d.ts +2 -0
- package/dist/map/frame-loop.js +3 -3
- package/dist/map/frame-loop.js.map +1 -1
- package/dist/map.js +17 -0
- package/dist/map.js.map +1 -1
- package/dist/panoramax.d.ts +19 -0
- package/dist/panoramax.js +48 -3
- package/dist/panoramax.js.map +1 -1
- package/dist/react/CustomLayer.js +5 -4
- package/dist/react/CustomLayer.js.map +1 -1
- package/dist/react/Layer.d.ts +1 -1
- package/dist/react/Layer.js +6 -5
- package/dist/react/Layer.js.map +1 -1
- package/dist/react/VectorGeometry.d.ts +18 -9
- package/dist/react/VectorGeometry.js +30 -15
- package/dist/react/VectorGeometry.js.map +1 -1
- package/dist/react/VectorTiles.d.ts +65 -0
- package/dist/react/VectorTiles.js +112 -0
- package/dist/react/VectorTiles.js.map +1 -0
- package/dist/react/context.d.ts +12 -0
- package/dist/react/context.js +40 -1
- package/dist/react/context.js.map +1 -1
- package/dist/react/index.d.ts +7 -1
- package/dist/react/index.js +7 -1
- package/dist/react/index.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.js.map +1 -1
- package/dist/util/geo.d.ts +8 -0
- package/dist/util/geo.js +8 -0
- package/dist/util/geo.js.map +1 -1
- package/dist/util/gltf.d.ts +18 -1
- package/dist/util/gltf.js +26 -1
- package/dist/util/gltf.js.map +1 -1
- package/dist/util/roofs.d.ts +8 -0
- package/dist/util/roofs.js +16 -2
- package/dist/util/roofs.js.map +1 -1
- package/dist/util/style-floats.d.ts +33 -0
- package/dist/util/style-floats.js +34 -0
- package/dist/util/style-floats.js.map +1 -0
- package/dist/util/sun.js +1 -1
- package/dist/util/sun.js.map +1 -1
- package/dist/workers/basemap/furniture.d.ts +13 -0
- package/dist/workers/basemap/geometry.d.ts +2 -5
- package/dist/workers/basemap/labels.d.ts +5 -2
- package/dist/workers/basemap/lamps.d.ts +3 -3
- package/dist/workers/basemap/tiles.d.ts +2 -0
- package/dist/workers/basemap/trees.d.ts +3 -0
- package/dist/workers/basemap.worker.d.ts +17 -1
- package/dist/workers/basemap.worker.js +12 -1
- package/dist/workers/basemap.worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,90 +1,25 @@
|
|
|
1
1
|
/** The street lamps of a vector basemap (`VectorTiles.lamps`): 3D models placed by the workers along its streets, lit at
|
|
2
2
|
* night */
|
|
3
3
|
import { LAMP_HEAD, lampModel } from "../furniture.js";
|
|
4
|
-
import {
|
|
5
|
-
import { TileRequests } from "./requests.js";
|
|
6
|
-
import { nearPriority, tileKey, tilesAround } from "./tiles.js";
|
|
7
|
-
import { followWhenMoved, groundUnderCamera, METRES_PER_DEGREE } from "./trees.js";
|
|
4
|
+
import { placed } from "./placed.js";
|
|
8
5
|
import { isStreet } from "./vectors.js";
|
|
9
6
|
/** Metres around the ground under the camera where every lamp is drawn at zoom 17 (twice as far a zoom level out);
|
|
10
7
|
* past them, fewer and fewer */
|
|
11
8
|
const LAMPS_NEAR_METRES = 250;
|
|
12
9
|
export const lamps = (context, options = {}) => {
|
|
13
|
-
const { map } = context;
|
|
14
10
|
const { layers = isStreet, spacing = 30, minZoom = 16, maxTiles = 9, maxLamps = 20000, maxInstances = 15000, light = '#ffd9a0', } = options;
|
|
15
|
-
const layer =
|
|
16
|
-
data: lampModel(),
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
const [layer] = placed(context, {
|
|
12
|
+
models: [{ data: lampModel() }],
|
|
13
|
+
layers: (l) => l.type === 'line' && layers(l),
|
|
14
|
+
work: (key, z, x, y, priority) => ({ type: 'lamps', key, z, x, y, spacing, maxLamps, priority }),
|
|
15
|
+
read: (r) => ('lamps' in r ? r.lamps : undefined),
|
|
16
|
+
near: [LAMPS_NEAR_METRES, 17],
|
|
17
|
+
minZoom,
|
|
18
|
+
maxTiles,
|
|
19
|
+
maxInstances,
|
|
20
|
+
...(options.before && { before: options.before }),
|
|
19
21
|
});
|
|
20
|
-
const renderer = context.renderer((l) => l.type === 'line' && layers(l), []);
|
|
21
22
|
layer.setGlow(LAMP_HEAD, light);
|
|
22
|
-
renderer.catch(() => undefined);
|
|
23
|
-
context.layers.push(layer);
|
|
24
|
-
const requests = new TileRequests();
|
|
25
|
-
const found = new Map();
|
|
26
|
-
/** The lamps drawn: all of them near the ground under the camera, past it those of a rank under (near / distance)²,
|
|
27
|
-
* at most `maxInstances` (past it, the rank kept lowered in proportion: no sort) */
|
|
28
|
-
const send = () => {
|
|
29
|
-
const { center, zoom } = map.getCamera();
|
|
30
|
-
const cos = Math.cos((center[1] * Math.PI) / 180);
|
|
31
|
-
const [ex, ey, back] = groundUnderCamera(map);
|
|
32
|
-
const near = LAMPS_NEAR_METRES * 2 ** (17 - zoom) + back;
|
|
33
|
-
const each = (keep) => {
|
|
34
|
-
found.forEach((t) => {
|
|
35
|
-
for (let i = 0; i < t.length / TREE_NUMBERS; i += 1) {
|
|
36
|
-
const dx = ((t[i * TREE_NUMBERS] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;
|
|
37
|
-
const dy = ((t[i * TREE_NUMBERS + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;
|
|
38
|
-
const score = (t[i * TREE_NUMBERS + 4] ?? 0) * Math.max(1, (dx * dx + dy * dy) / (near * near));
|
|
39
|
-
if (score < 1)
|
|
40
|
-
keep(t, i, score);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
let count = 0;
|
|
45
|
-
each(() => {
|
|
46
|
-
count += 1;
|
|
47
|
-
});
|
|
48
|
-
const limit = Math.min(1, maxInstances / Math.max(count, 1));
|
|
49
|
-
const out = [];
|
|
50
|
-
each((t, i, score) => {
|
|
51
|
-
const at = i * TREE_NUMBERS;
|
|
52
|
-
if (score < limit)
|
|
53
|
-
out.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);
|
|
54
|
-
});
|
|
55
|
-
layer.setInstanceNumbers(Float64Array.from(out));
|
|
56
|
-
};
|
|
57
|
-
const update = async () => {
|
|
58
|
-
if (context.destroyed())
|
|
59
|
-
return;
|
|
60
|
-
const { key, maxzoom } = await renderer;
|
|
61
|
-
const camera = map.getCamera();
|
|
62
|
-
const z = maxzoom;
|
|
63
|
-
const wanted = camera.zoom < minZoom ? [] : tilesAround(map, camera, z, maxTiles);
|
|
64
|
-
const keys = new Set(wanted.map(([x, y]) => tileKey(z, x, y)));
|
|
65
|
-
// Out of view: dropped, or no longer asked for
|
|
66
|
-
requests
|
|
67
|
-
.keys()
|
|
68
|
-
.filter((k) => !keys.has(k))
|
|
69
|
-
.forEach((k) => {
|
|
70
|
-
requests.drop(k);
|
|
71
|
-
found.delete(k);
|
|
72
|
-
});
|
|
73
|
-
send();
|
|
74
|
-
wanted.forEach(([x, y], index) => {
|
|
75
|
-
const k = tileKey(z, x, y);
|
|
76
|
-
if (requests.has(k))
|
|
77
|
-
return;
|
|
78
|
-
const work = { type: 'lamps', key, z, x, y, spacing, maxLamps, priority: nearPriority(index) };
|
|
79
|
-
requests.ask(k, (signal) => context.request(z, x, y, work, signal), (r) => {
|
|
80
|
-
if (!('lamps' in r))
|
|
81
|
-
return;
|
|
82
|
-
found.set(k, r.lamps);
|
|
83
|
-
send();
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
};
|
|
87
|
-
context.followView(update, requests, followWhenMoved(map, (zoom) => LAMPS_NEAR_METRES * 2 ** (17 - zoom), send));
|
|
88
23
|
return layer;
|
|
89
24
|
};
|
|
90
25
|
//# sourceMappingURL=lamps.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lamps.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/lamps.ts"],"names":[],"mappings":"AAAA;WACW;
|
|
1
|
+
{"version":3,"file":"lamps.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/lamps.ts"],"names":[],"mappings":"AAAA;WACW;AAGX,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC;gCACgC;AAChC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAoB9B,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,OAA2B,EAAE,UAAwB,EAAE,EAAc,EAAE;IAC3F,MAAM,EACJ,MAAM,GAAG,QAAQ,EACjB,OAAO,GAAG,EAAE,EACZ,OAAO,GAAG,EAAE,EACZ,QAAQ,GAAG,CAAC,EACZ,QAAQ,GAAG,KAAK,EAChB,YAAY,GAAG,KAAK,EACpB,KAAK,GAAG,SAAS,GAClB,GAAG,OAAO,CAAC;IACZ,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE;QAC9B,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;QAC/B,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QAChG,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACjD,IAAI,EAAE,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC7B,OAAO;QACP,QAAQ;QACR,YAAY;QACZ,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;KAClD,CAAC,CAAC;IAEH,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAEhC,OAAO,KAAK,CAAC;AACf,CAAC,CAAC","sourcesContent":["/** The street lamps of a vector basemap (`VectorTiles.lamps`): 3D models placed by the workers along its streets, lit at\n * night */\n\nimport type { Layer, ModelLayer } from '../../layers/layers.ts';\nimport { LAMP_HEAD, lampModel } from '../furniture.ts';\nimport type { StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { placed } from './placed.ts';\nimport { isStreet } from './vectors.ts';\n\n/** Metres around the ground under the camera where every lamp is drawn at zoom 17 (twice as far a zoom level out);\n * past them, fewer and fewer */\nconst LAMPS_NEAR_METRES = 250;\n\n/** The options of `VectorTiles.lamps` */\nexport interface LampsOptions {\n /** The line layers of the streets lit (default: the roads, as the streets glowing at night) */\n layers?: (layer: StyleLayer) => boolean;\n /** Metres between two lamps along a street (default 30, every other one on its other side) */\n spacing?: number;\n /** From this zoom on (default 16) */\n minZoom?: number;\n maxTiles?: number;\n /** Lamps in a tile at most (default 20000) */\n maxLamps?: number;\n /** Lamps drawn at most (default 15000) */\n maxInstances?: number;\n /** The color of their light at night (CSS; default a warm white) */\n light?: string;\n before?: Layer;\n}\n\nexport const lamps = (context: VectorTilesContext, options: LampsOptions = {}): ModelLayer => {\n const {\n layers = isStreet,\n spacing = 30,\n minZoom = 16,\n maxTiles = 9,\n maxLamps = 20000,\n maxInstances = 15000,\n light = '#ffd9a0',\n } = options;\n const [layer] = placed(context, {\n models: [{ data: lampModel() }],\n layers: (l) => l.type === 'line' && layers(l),\n work: (key, z, x, y, priority) => ({ type: 'lamps', key, z, x, y, spacing, maxLamps, priority }),\n read: (r) => ('lamps' in r ? r.lamps : undefined),\n near: [LAMPS_NEAR_METRES, 17],\n minZoom,\n maxTiles,\n maxInstances,\n ...(options.before && { before: options.before }),\n });\n\n layer.setGlow(LAMP_HEAD, light);\n\n return layer;\n};\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Things placed by the workers in a vector basemap's tiles around the view (trees, street lamps, street furniture),
|
|
3
|
+
* each kind one instanced model layer: all of them near the ground under the camera, fewer and fewer past it (a
|
|
4
|
+
* simplified model there when the kind has one), the tiles following the view.
|
|
5
|
+
*/
|
|
6
|
+
import type { Layer, ModelLayer, ModelOptions } from '../../layers/layers.ts';
|
|
7
|
+
import type { BasemapResponse, BasemapWork, Priority } from '../../workers/basemap.worker.ts';
|
|
8
|
+
import type { StyleLayer } from '../vectorstyle.ts';
|
|
9
|
+
import type { VectorTilesContext } from './context.ts';
|
|
10
|
+
/** A model: a glTF binary's URL or bytes */
|
|
11
|
+
type Model = Pick<ModelOptions, 'url' | 'data'>;
|
|
12
|
+
interface PlacedOptions {
|
|
13
|
+
/** A model per kind (`PLACED_KIND`); a kind past them drawn with the first */
|
|
14
|
+
models: [Model, ...Model[]];
|
|
15
|
+
/** Past `near`, the kinds' simplified models (as many), drawn `density` times as densely as the full ones would
|
|
16
|
+
* be, at most `instances` times `maxInstances` */
|
|
17
|
+
far?: {
|
|
18
|
+
models: Model[];
|
|
19
|
+
density: number;
|
|
20
|
+
instances: number;
|
|
21
|
+
};
|
|
22
|
+
/** The style layers the renderer sends the workers (the tiles' source and its levels) */
|
|
23
|
+
layers: (layer: StyleLayer) => boolean;
|
|
24
|
+
/** The work asked of the worker of a tile (`layers`: the renderer's), and the things in its answer */
|
|
25
|
+
work: (key: string, z: number, x: number, y: number, priority: Priority, layers: StyleLayer[]) => BasemapWork;
|
|
26
|
+
read: (response: BasemapResponse) => Float64Array | undefined;
|
|
27
|
+
/** Metres around the ground under the camera where every one is drawn at a zoom (twice as far a zoom level out) */
|
|
28
|
+
near: [metres: number, zoom: number];
|
|
29
|
+
minZoom: number;
|
|
30
|
+
maxTiles: number;
|
|
31
|
+
/** Things drawn at most, all kinds together (and `far.instances` times as many simplified) */
|
|
32
|
+
maxInstances: number;
|
|
33
|
+
before?: Layer;
|
|
34
|
+
}
|
|
35
|
+
/** The layers of the things placed: one per kind, then one per kind's simplified model; the first holds the others
|
|
36
|
+
* (`Layer.companions`) */
|
|
37
|
+
export declare const placed: (context: VectorTilesContext, options: PlacedOptions) => [ModelLayer, ...ModelLayer[]];
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Things placed by the workers in a vector basemap's tiles around the view (trees, street lamps, street furniture),
|
|
3
|
+
* each kind one instanced model layer: all of them near the ground under the camera, fewer and fewer past it (a
|
|
4
|
+
* simplified model there when the kind has one), the tiles following the view.
|
|
5
|
+
*/
|
|
6
|
+
import { METRES_PER_DEGREE } from "../../util/geo.js";
|
|
7
|
+
import { PLACED_KIND, PLACED_NUMBERS, PLACED_RANK } from "../placed.js";
|
|
8
|
+
import { TileRequests } from "./requests.js";
|
|
9
|
+
import { nearPriority, tileKey, tilesAround } from "./tiles.js";
|
|
10
|
+
/** The engine's vertical field of view (radians, `camera::FOV`): where the camera stands behind the view's center */
|
|
11
|
+
const FOV = 0.6435011087932844;
|
|
12
|
+
/** While the camera moves, the things chosen again once it has gone this share of the near radius (or turned or
|
|
13
|
+
* zoomed as much): going through the tiles' things at every frame of a drag would hold the main thread */
|
|
14
|
+
const RESEND_SHARE = 0.05;
|
|
15
|
+
/** The ground under the camera: east and north metres from the view's center, and its distance from it (the camera
|
|
16
|
+
* stands behind the center of a tilted view, `FOV` its field of view) */
|
|
17
|
+
const groundUnderCamera = (map) => {
|
|
18
|
+
const { pitch, bearing } = map.getCamera();
|
|
19
|
+
const back = ((0.5 * map.getCanvas().clientHeight) / Math.tan(FOV / 2)) *
|
|
20
|
+
Math.sin((pitch * Math.PI) / 180) *
|
|
21
|
+
(map.metersPerPixel() ?? 0);
|
|
22
|
+
return [-back * Math.sin((bearing * Math.PI) / 180), -back * Math.cos((bearing * Math.PI) / 180), back];
|
|
23
|
+
};
|
|
24
|
+
/** What follows the camera as it moves: `send` called again once it has gone `RESEND_SHARE` of `radius` metres (or
|
|
25
|
+
* turned or zoomed as much), not at every frame of a drag */
|
|
26
|
+
const followWhenMoved = (map, radius, send) => {
|
|
27
|
+
/** The view of the last call: center (metres), zoom, bearing, pitch */
|
|
28
|
+
let sent;
|
|
29
|
+
return () => {
|
|
30
|
+
const { center, zoom, bearing, pitch } = map.getCamera();
|
|
31
|
+
const [x, y] = [
|
|
32
|
+
center[0] * METRES_PER_DEGREE * Math.cos((center[1] * Math.PI) / 180),
|
|
33
|
+
center[1] * METRES_PER_DEGREE,
|
|
34
|
+
];
|
|
35
|
+
if (sent &&
|
|
36
|
+
Math.hypot(x - sent[0], y - sent[1]) < RESEND_SHARE * radius(zoom) &&
|
|
37
|
+
Math.abs(zoom - sent[2]) < RESEND_SHARE &&
|
|
38
|
+
Math.abs(bearing - sent[3]) < 45 * RESEND_SHARE &&
|
|
39
|
+
Math.abs(pitch - sent[4]) < 45 * RESEND_SHARE)
|
|
40
|
+
return;
|
|
41
|
+
sent = [x, y, zoom, bearing, pitch];
|
|
42
|
+
send();
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/** The layers of the things placed: one per kind, then one per kind's simplified model; the first holds the others
|
|
46
|
+
* (`Layer.companions`) */
|
|
47
|
+
export const placed = (context, options) => {
|
|
48
|
+
const { map } = context;
|
|
49
|
+
const { models, far, minZoom, maxTiles, maxInstances } = options;
|
|
50
|
+
const add = (model) => map.addModels({ ...model, instances: [], ...(options.before ? { before: options.before } : {}) });
|
|
51
|
+
const [model, ...more] = models;
|
|
52
|
+
const layers = [add(model), ...more.map(add), ...(far?.models ?? []).map(add)];
|
|
53
|
+
const renderer = context.renderer(options.layers, []);
|
|
54
|
+
const radius = (zoom) => options.near[0] * 2 ** (options.near[1] - zoom);
|
|
55
|
+
renderer.catch(() => undefined);
|
|
56
|
+
layers[0].companions.push(...layers.slice(1));
|
|
57
|
+
context.layers.push(...layers);
|
|
58
|
+
const requests = new TileRequests();
|
|
59
|
+
const found = new Map();
|
|
60
|
+
/** The things drawn: all of them near the ground under the camera; past it those of a rank under `density` (near /
|
|
61
|
+
* distance)², simplified; at most `maxInstances` near, `far.instances` times as many past (beyond, the rank kept
|
|
62
|
+
* lowered in proportion: no sort) */
|
|
63
|
+
const send = () => {
|
|
64
|
+
const { center, zoom } = map.getCamera();
|
|
65
|
+
const cos = Math.cos((center[1] * Math.PI) / 180);
|
|
66
|
+
const [ex, ey, back] = groundUnderCamera(map);
|
|
67
|
+
const near = radius(zoom) + back;
|
|
68
|
+
const density = far?.density ?? 1;
|
|
69
|
+
/** Each thing that may be drawn: in full (near, or every one without simplified models) or simplified, with its
|
|
70
|
+
* score (the lowest kept first) */
|
|
71
|
+
const visit = (each) => {
|
|
72
|
+
found.forEach((t) => {
|
|
73
|
+
for (let at = 0; at < t.length; at += PLACED_NUMBERS) {
|
|
74
|
+
const dx = ((t[at] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;
|
|
75
|
+
const dy = ((t[at + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;
|
|
76
|
+
const distance = (dx * dx + dy * dy) / (near * near);
|
|
77
|
+
const rank = t[at + PLACED_RANK] ?? 0;
|
|
78
|
+
if (distance <= 1)
|
|
79
|
+
each(t, at, true, rank);
|
|
80
|
+
else if (rank * (distance / density) < 1)
|
|
81
|
+
each(t, at, !far, rank * (distance / density));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
let [fullCount, farCount] = [0, 0];
|
|
86
|
+
visit((_, __, full) => {
|
|
87
|
+
if (full)
|
|
88
|
+
fullCount += 1;
|
|
89
|
+
else
|
|
90
|
+
farCount += 1;
|
|
91
|
+
});
|
|
92
|
+
const limits = [
|
|
93
|
+
Math.min(1, maxInstances / Math.max(fullCount, 1)),
|
|
94
|
+
Math.min(1, (maxInstances * (far?.instances ?? 1)) / Math.max(farCount, 1)),
|
|
95
|
+
];
|
|
96
|
+
// The engine's numbers: longitude, latitude, altitude, heading, pitch, roll, scale
|
|
97
|
+
const out = layers.map(() => []);
|
|
98
|
+
visit((t, at, full, score) => {
|
|
99
|
+
if (score >= (limits[full ? 0 : 1] ?? 1))
|
|
100
|
+
return;
|
|
101
|
+
const kind = t[at + PLACED_KIND] ?? 0;
|
|
102
|
+
const k = (full ? 0 : models.length) + (kind < models.length ? kind : 0);
|
|
103
|
+
out[k]?.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);
|
|
104
|
+
});
|
|
105
|
+
layers.forEach((layer, k) => {
|
|
106
|
+
layer.setInstanceNumbers(Float64Array.from(out[k] ?? []));
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
const update = async () => {
|
|
110
|
+
if (context.destroyed())
|
|
111
|
+
return;
|
|
112
|
+
const { key, maxzoom: z, layers: list } = await renderer;
|
|
113
|
+
const camera = map.getCamera();
|
|
114
|
+
const wanted = camera.zoom < minZoom ? [] : tilesAround(map, camera, z, maxTiles);
|
|
115
|
+
const keys = new Set(wanted.map(([x, y]) => tileKey(z, x, y)));
|
|
116
|
+
// Out of view: dropped, or no longer asked for
|
|
117
|
+
requests
|
|
118
|
+
.keys()
|
|
119
|
+
.filter((k) => !keys.has(k))
|
|
120
|
+
.forEach((k) => {
|
|
121
|
+
requests.drop(k);
|
|
122
|
+
found.delete(k);
|
|
123
|
+
});
|
|
124
|
+
// Dense around the new center
|
|
125
|
+
send();
|
|
126
|
+
wanted.forEach(([x, y], index) => {
|
|
127
|
+
const k = tileKey(z, x, y);
|
|
128
|
+
if (requests.has(k))
|
|
129
|
+
return;
|
|
130
|
+
requests.ask(k, (signal) => context.request(z, x, y, options.work(key, z, x, y, nearPriority(index), list), signal), (r) => {
|
|
131
|
+
const things = options.read(r);
|
|
132
|
+
if (!things)
|
|
133
|
+
return;
|
|
134
|
+
found.set(k, things);
|
|
135
|
+
send();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
// While the camera moves, the things drawn follow it (dense near it), chosen again once it has gone far enough
|
|
140
|
+
context.followView(layers[0], update, requests, followWhenMoved(map, radius, send));
|
|
141
|
+
return layers;
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=placed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placed.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/placed.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Things placed by the workers in a vector basemap's tiles around the view (trees, street lamps, street furniture),\n * each kind one instanced model layer: all of them near the ground under the camera, fewer and fewer past it (a\n * simplified model there when the kind has one), the tiles following the view.\n */\n\nimport type { Layer, ModelLayer, ModelOptions } from '../../layers/layers.ts';\nimport type { GeoMap } from '../../map.ts';\nimport { METRES_PER_DEGREE } from '../../util/geo.ts';\nimport type { BasemapResponse, BasemapWork, Priority } from '../../workers/basemap.worker.ts';\nimport { PLACED_KIND, PLACED_NUMBERS, PLACED_RANK } from '../placed.ts';\nimport type { StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { TileRequests } from './requests.ts';\nimport { nearPriority, tileKey, tilesAround } from './tiles.ts';\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/** While the camera moves, the things chosen again once it has gone this share of the near radius (or turned or\n * zoomed as much): going through the tiles' things at every frame of a drag would hold the main thread */\nconst RESEND_SHARE = 0.05;\n\n/** A model: a glTF binary's URL or bytes */\ntype Model = Pick<ModelOptions, 'url' | 'data'>;\n\ninterface PlacedOptions {\n /** A model per kind (`PLACED_KIND`); a kind past them drawn with the first */\n models: [Model, ...Model[]];\n /** Past `near`, the kinds' simplified models (as many), drawn `density` times as densely as the full ones would\n * be, at most `instances` times `maxInstances` */\n far?: { models: Model[]; density: number; instances: number };\n /** The style layers the renderer sends the workers (the tiles' source and its levels) */\n layers: (layer: StyleLayer) => boolean;\n /** The work asked of the worker of a tile (`layers`: the renderer's), and the things in its answer */\n work: (key: string, z: number, x: number, y: number, priority: Priority, layers: StyleLayer[]) => BasemapWork;\n read: (response: BasemapResponse) => Float64Array | undefined;\n /** Metres around the ground under the camera where every one is drawn at a zoom (twice as far a zoom level out) */\n near: [metres: number, zoom: number];\n minZoom: number;\n maxTiles: number;\n /** Things drawn at most, all kinds together (and `far.instances` times as many simplified) */\n maxInstances: number;\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) */\nconst 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 */\nconst 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\n/** The layers of the things placed: one per kind, then one per kind's simplified model; the first holds the others\n * (`Layer.companions`) */\nexport const placed = (context: VectorTilesContext, options: PlacedOptions): [ModelLayer, ...ModelLayer[]] => {\n const { map } = context;\n const { models, far, minZoom, maxTiles, maxInstances } = options;\n const add = (model: Model) =>\n map.addModels({ ...model, instances: [], ...(options.before ? { before: options.before } : {}) });\n const [model, ...more] = models;\n const layers: [ModelLayer, ...ModelLayer[]] = [add(model), ...more.map(add), ...(far?.models ?? []).map(add)];\n const renderer = context.renderer(options.layers, []);\n const radius = (zoom: number) => options.near[0] * 2 ** (options.near[1] - zoom);\n\n renderer.catch(() => undefined);\n layers[0].companions.push(...layers.slice(1));\n context.layers.push(...layers);\n\n const requests = new TileRequests();\n const found = new Map<string, Float64Array>();\n /** The things drawn: all of them near the ground under the camera; past it those of a rank under `density` (near /\n * distance)², simplified; at most `maxInstances` near, `far.instances` times as many past (beyond, the rank kept\n * lowered in proportion: no sort) */\n const send = () => {\n const { center, zoom } = map.getCamera();\n const cos = Math.cos((center[1] * Math.PI) / 180);\n const [ex, ey, back] = groundUnderCamera(map);\n const near = radius(zoom) + back;\n const density = far?.density ?? 1;\n /** Each thing that may be drawn: in full (near, or every one without simplified models) or simplified, with its\n * score (the lowest kept first) */\n const visit = (each: (t: Float64Array, at: number, full: boolean, score: number) => void) => {\n found.forEach((t) => {\n for (let at = 0; at < t.length; at += PLACED_NUMBERS) {\n const dx = ((t[at] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;\n const dy = ((t[at + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;\n const distance = (dx * dx + dy * dy) / (near * near);\n const rank = t[at + PLACED_RANK] ?? 0;\n\n if (distance <= 1) each(t, at, true, rank);\n else if (rank * (distance / density) < 1) each(t, at, !far, rank * (distance / density));\n }\n });\n };\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 ?? 1)) / Math.max(farCount, 1)),\n ];\n // The engine's numbers: longitude, latitude, altitude, heading, pitch, roll, scale\n const out: number[][] = layers.map(() => []);\n\n visit((t, at, full, score) => {\n if (score >= (limits[full ? 0 : 1] ?? 1)) return;\n\n const kind = t[at + PLACED_KIND] ?? 0;\n const k = (full ? 0 : models.length) + (kind < models.length ? kind : 0);\n\n out[k]?.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);\n });\n layers.forEach((layer, k) => {\n layer.setInstanceNumbers(Float64Array.from(out[k] ?? []));\n });\n };\n const update = async () => {\n if (context.destroyed()) return;\n\n const { key, maxzoom: z, layers: list } = await renderer;\n const camera = map.getCamera();\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\n // Out of view: dropped, or no longer asked for\n requests\n .keys()\n .filter((k) => !keys.has(k))\n .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 requests.ask(\n k,\n (signal) => context.request(z, x, y, options.work(key, z, x, y, nearPriority(index), list), signal),\n (r) => {\n const things = options.read(r);\n\n if (!things) return;\n found.set(k, things);\n send();\n },\n );\n });\n };\n\n // While the camera moves, the things drawn follow it (dense near it), chosen again once it has gone far enough\n context.followView(layers[0], update, requests, followWhenMoved(map, radius, send));\n\n return layers;\n};\n"]}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/** The wind through the streets of a vector basemap (`VectorTiles.streetWind`): a flow round its buildings */
|
|
2
|
-
import { latitude, longitude, mercatorX, mercatorY } from "../../util/geo.js";
|
|
2
|
+
import { EARTH_METRES, latitude, longitude, mercatorX, mercatorY } from "../../util/geo.js";
|
|
3
3
|
import { TileRequests } from "./requests.js";
|
|
4
4
|
import { isBuildings, isPolygonLayer } from "./style.js";
|
|
5
5
|
import { STREET_ZOOM } from "./tiles.js";
|
|
6
|
-
/** Earth's circumference at the equator (metres): the size of the Mercator square, 1 wide, at latitude 0 */
|
|
7
|
-
const EARTH_CIRCUMFERENCE_METRES = 40_075_016.686;
|
|
8
6
|
/** Pause before the first square that failed is asked for again (ms) */
|
|
9
7
|
const RETRY_FIRST_MS = 1000;
|
|
10
8
|
/** Longest pause before a square that failed again and again is asked for again (ms) */
|
|
@@ -46,7 +44,7 @@ export const streetWind = (context, options = {}) => {
|
|
|
46
44
|
const camera = map.getCamera();
|
|
47
45
|
const [x, y] = [mercatorX(camera.center[0]), mercatorY(camera.center[1])];
|
|
48
46
|
// Half the square in Mercator, at its latitude
|
|
49
|
-
const half = size / 2 / (
|
|
47
|
+
const half = size / 2 / (EARTH_METRES * Math.cos((camera.center[1] * Math.PI) / 180));
|
|
50
48
|
const square = state.square;
|
|
51
49
|
// Off street level: no square (its particles gone, asked for again back at street level)
|
|
52
50
|
if (camera.zoom < minZoom) {
|
|
@@ -118,8 +116,8 @@ export const streetWind = (context, options = {}) => {
|
|
|
118
116
|
};
|
|
119
117
|
renderer.catch(() => undefined);
|
|
120
118
|
context.layers.push(layer);
|
|
121
|
-
context.followView(update, requests, () => undefined);
|
|
122
|
-
context.
|
|
119
|
+
context.followView(layer, update, requests, () => undefined);
|
|
120
|
+
context.stopWith(layer, () => {
|
|
123
121
|
clearTimeout(state.retry);
|
|
124
122
|
});
|
|
125
123
|
return Object.assign(layer, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"street-wind.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/street-wind.ts"],"names":[],"mappings":"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","sourcesContent":["/** The wind through the streets of a vector basemap (`VectorTiles.streetWind`): a flow round its buildings */\n\nimport type { StreetFlows } from '../../grid-module.ts';\nimport type { FlowField, FlowLayer, FlowOptions } from '../../layers/flow.ts';\nimport { latitude, longitude, mercatorX, mercatorY } from '../../util/geo.ts';\nimport type { BasemapWork } from '../../workers/basemap.worker.ts';\nimport type { StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { TileRequests } from './requests.ts';\nimport { isBuildings, isPolygonLayer } from './style.ts';\nimport { STREET_ZOOM } from './tiles.ts';\n\n/** Earth's circumference at the equator (metres): the size of the Mercator square, 1 wide, at latitude 0 */\nconst EARTH_CIRCUMFERENCE_METRES = 40_075_016.686;\n\n/** Pause before the first square that failed is asked for again (ms) */\nconst RETRY_FIRST_MS = 1000;\n\n/** Longest pause before a square that failed again and again is asked for again (ms) */\nconst RETRY_MAX_MS = 30_000;\n\n/** The options of `VectorTiles.streetWind` */\nexport type StreetWindOptions = Omit<FlowOptions, 'field' | 'fields' | 'time'> & {\n wind?: [u: number, v: number];\n size?: number;\n cell?: number;\n iterations?: number;\n layers?: (layer: StyleLayer) => boolean;\n minZoom?: number;\n};\n\n/** The layer of `VectorTiles.streetWind` */\nexport type StreetWindLayer = FlowLayer & { setWind(wind: [u: number, v: number]): void; computed: Promise<void> };\n\nexport const streetWind = (context: VectorTilesContext, options: StreetWindOptions = {}): StreetWindLayer => {\n const { map } = context;\n const { size = 1200, cell = 4, iterations = 300, layers = isBuildings, minZoom = STREET_ZOOM, ...flow } = options;\n const renderer = context.renderer(isPolygonLayer(layers), []);\n /** No square: a field of no value at the view's center, where no particle is born nor moves (the map idles) */\n const empty = (): FlowField => {\n const [lon, lat] = map.getCamera().center;\n\n return {\n width: 2,\n height: 2,\n u: [NaN, NaN, NaN, NaN],\n v: [NaN, NaN, NaN, NaN],\n bounds: [lon, lat, lon + 1e-4, lat + 1e-4],\n };\n };\n const layer = map.addFlow({ height: 3, ...flow, field: empty() });\n const state: {\n wind: [number, number];\n /** The square solved (Mercator: west, north, east, south), its grid, the flows of its basis */\n square?: [number, number, number, number] | undefined;\n grid?: { width: number; height: number; bounds: [number, number, number, number] };\n flows?: StreetFlows | undefined;\n /** Bumped by each square asked for: only the last one's answer is taken */\n asked: number;\n /** After a failure, the square asked for again in `wait` ms (doubled each time) */\n retry?: number;\n wait: number;\n } = { wind: options.wind ?? [3, 2], asked: 0, wait: RETRY_FIRST_MS };\n /** The flow of the wind far away: `u` times the flow towards the east plus `v` times the one towards the north,\n * mixed by the engine (the two flows sent once a square, a new wind two numbers) */\n const send = () => {\n const { flows, grid, wind } = state;\n\n if (!flows || !grid) return;\n layer.setBasis({ ...grid, u: flows.eastU, v: flows.eastV }, { ...grid, u: flows.northU, v: flows.northV }, wind);\n };\n /** The square asked for, its only request (under `square`) */\n const requests = new TileRequests();\n const first: { resolve?: () => void } = {};\n const computed = new Promise<void>((resolve) => {\n first.resolve = resolve;\n });\n const update = async () => {\n if (context.destroyed()) return;\n\n const camera = map.getCamera();\n const [x, y] = [mercatorX(camera.center[0]), mercatorY(camera.center[1])];\n // Half the square in Mercator, at its latitude\n const half = size / 2 / (EARTH_CIRCUMFERENCE_METRES * Math.cos((camera.center[1] * Math.PI) / 180));\n const square = state.square;\n\n // Off street level: no square (its particles gone, asked for again back at street level)\n if (camera.zoom < minZoom) {\n if (state.square) {\n state.asked++;\n state.square = undefined;\n state.flows = undefined;\n requests.abortAll();\n layer.setField(empty());\n }\n\n return;\n }\n // Still in the square's middle: nothing to compute\n if (\n square &&\n Math.abs(x - (square[0] + square[2]) / 2) < half / 3 &&\n Math.abs(y - (square[1] + square[3]) / 2) < half / 3\n ) {\n return;\n }\n\n const { key, maxzoom } = await renderer;\n const bounds: [number, number, number, number] = [x - half, y - half, x + half, y + half];\n const n = 2 ** maxzoom;\n const tiles: number[] = [];\n\n for (let ty = Math.floor(bounds[1] * n); ty <= Math.floor(bounds[3] * n); ty++) {\n for (let tx = Math.floor(bounds[0] * n); tx <= Math.floor(bounds[2] * n); tx++) tiles.push(tx, ty);\n }\n\n const sides = Math.max(8, Math.round(size / cell));\n const work: BasemapWork = {\n type: 'street',\n key,\n module: map.gridUrl,\n z: maxzoom,\n tiles,\n bounds,\n width: sides,\n height: sides,\n iterations,\n };\n const asked = ++state.asked;\n\n requests.abortAll();\n\n const signal = requests.start('square');\n\n state.square = bounds;\n\n const answer = await context\n .request(maxzoom, Math.floor(x * n), Math.floor(y * n), work, signal)\n .catch((error: unknown) => ({ error }));\n\n if (asked !== state.asked || signal.aborted) return;\n // Failed (a tile or the grid module not fetched, a worker of an older build): the square asked for again later,\n // a while after each failure\n if (!('street' in answer)) {\n console.warn(\"isard: the streets' wind not computed, tried again\", 'error' in answer ? answer.error : answer);\n state.square = undefined;\n clearTimeout(state.retry);\n state.retry = window.setTimeout(() => {\n update().catch(() => undefined);\n }, state.wait);\n state.wait = Math.min(state.wait * 2, RETRY_MAX_MS);\n\n return;\n }\n state.wait = RETRY_FIRST_MS;\n state.flows = answer.street;\n state.grid = {\n width: sides,\n height: sides,\n bounds: [longitude(bounds[0]), latitude(bounds[3]), longitude(bounds[2]), latitude(bounds[1])],\n };\n send();\n first.resolve?.();\n };\n\n renderer.catch(() => undefined);\n context.layers.push(layer);\n context.followView(update, requests, () => undefined);\n context.cleanup.push(() => {\n clearTimeout(state.retry);\n });\n\n return Object.assign(layer, {\n computed,\n setWind: (wind: [u: number, v: number]) => {\n state.wind = wind;\n layer.setWeights(wind);\n },\n });\n};\n"]}
|
|
1
|
+
{"version":3,"file":"street-wind.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/street-wind.ts"],"names":[],"mappings":"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","sourcesContent":["/** The wind through the streets of a vector basemap (`VectorTiles.streetWind`): a flow round its buildings */\n\nimport type { StreetFlows } from '../../grid-module.ts';\nimport type { FlowField, FlowLayer, FlowOptions } from '../../layers/flow.ts';\nimport { EARTH_METRES, latitude, longitude, mercatorX, mercatorY } from '../../util/geo.ts';\nimport type { BasemapWork } from '../../workers/basemap.worker.ts';\nimport type { StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { TileRequests } from './requests.ts';\nimport { isBuildings, isPolygonLayer } from './style.ts';\nimport { STREET_ZOOM } from './tiles.ts';\n\n/** Pause before the first square that failed is asked for again (ms) */\nconst RETRY_FIRST_MS = 1000;\n\n/** Longest pause before a square that failed again and again is asked for again (ms) */\nconst RETRY_MAX_MS = 30_000;\n\n/** The options of `VectorTiles.streetWind` */\nexport type StreetWindOptions = Omit<FlowOptions, 'field' | 'fields' | 'time'> & {\n wind?: [u: number, v: number];\n size?: number;\n cell?: number;\n iterations?: number;\n layers?: (layer: StyleLayer) => boolean;\n minZoom?: number;\n};\n\n/** The layer of `VectorTiles.streetWind` */\nexport type StreetWindLayer = FlowLayer & { setWind(wind: [u: number, v: number]): void; computed: Promise<void> };\n\nexport const streetWind = (context: VectorTilesContext, options: StreetWindOptions = {}): StreetWindLayer => {\n const { map } = context;\n const { size = 1200, cell = 4, iterations = 300, layers = isBuildings, minZoom = STREET_ZOOM, ...flow } = options;\n const renderer = context.renderer(isPolygonLayer(layers), []);\n /** No square: a field of no value at the view's center, where no particle is born nor moves (the map idles) */\n const empty = (): FlowField => {\n const [lon, lat] = map.getCamera().center;\n\n return {\n width: 2,\n height: 2,\n u: [NaN, NaN, NaN, NaN],\n v: [NaN, NaN, NaN, NaN],\n bounds: [lon, lat, lon + 1e-4, lat + 1e-4],\n };\n };\n const layer = map.addFlow({ height: 3, ...flow, field: empty() });\n const state: {\n wind: [number, number];\n /** The square solved (Mercator: west, north, east, south), its grid, the flows of its basis */\n square?: [number, number, number, number] | undefined;\n grid?: { width: number; height: number; bounds: [number, number, number, number] };\n flows?: StreetFlows | undefined;\n /** Bumped by each square asked for: only the last one's answer is taken */\n asked: number;\n /** After a failure, the square asked for again in `wait` ms (doubled each time) */\n retry?: number;\n wait: number;\n } = { wind: options.wind ?? [3, 2], asked: 0, wait: RETRY_FIRST_MS };\n /** The flow of the wind far away: `u` times the flow towards the east plus `v` times the one towards the north,\n * mixed by the engine (the two flows sent once a square, a new wind two numbers) */\n const send = () => {\n const { flows, grid, wind } = state;\n\n if (!flows || !grid) return;\n layer.setBasis({ ...grid, u: flows.eastU, v: flows.eastV }, { ...grid, u: flows.northU, v: flows.northV }, wind);\n };\n /** The square asked for, its only request (under `square`) */\n const requests = new TileRequests();\n const first: { resolve?: () => void } = {};\n const computed = new Promise<void>((resolve) => {\n first.resolve = resolve;\n });\n const update = async () => {\n if (context.destroyed()) return;\n\n const camera = map.getCamera();\n const [x, y] = [mercatorX(camera.center[0]), mercatorY(camera.center[1])];\n // Half the square in Mercator, at its latitude\n const half = size / 2 / (EARTH_METRES * Math.cos((camera.center[1] * Math.PI) / 180));\n const square = state.square;\n\n // Off street level: no square (its particles gone, asked for again back at street level)\n if (camera.zoom < minZoom) {\n if (state.square) {\n state.asked++;\n state.square = undefined;\n state.flows = undefined;\n requests.abortAll();\n layer.setField(empty());\n }\n\n return;\n }\n // Still in the square's middle: nothing to compute\n if (\n square &&\n Math.abs(x - (square[0] + square[2]) / 2) < half / 3 &&\n Math.abs(y - (square[1] + square[3]) / 2) < half / 3\n ) {\n return;\n }\n\n const { key, maxzoom } = await renderer;\n const bounds: [number, number, number, number] = [x - half, y - half, x + half, y + half];\n const n = 2 ** maxzoom;\n const tiles: number[] = [];\n\n for (let ty = Math.floor(bounds[1] * n); ty <= Math.floor(bounds[3] * n); ty++) {\n for (let tx = Math.floor(bounds[0] * n); tx <= Math.floor(bounds[2] * n); tx++) tiles.push(tx, ty);\n }\n\n const sides = Math.max(8, Math.round(size / cell));\n const work: BasemapWork = {\n type: 'street',\n key,\n module: map.gridUrl,\n z: maxzoom,\n tiles,\n bounds,\n width: sides,\n height: sides,\n iterations,\n };\n const asked = ++state.asked;\n\n requests.abortAll();\n\n const signal = requests.start('square');\n\n state.square = bounds;\n\n const answer = await context\n .request(maxzoom, Math.floor(x * n), Math.floor(y * n), work, signal)\n .catch((error: unknown) => ({ error }));\n\n if (asked !== state.asked || signal.aborted) return;\n // Failed (a tile or the grid module not fetched, a worker of an older build): the square asked for again later,\n // a while after each failure\n if (!('street' in answer)) {\n console.warn(\"isard: the streets' wind not computed, tried again\", 'error' in answer ? answer.error : answer);\n state.square = undefined;\n clearTimeout(state.retry);\n state.retry = window.setTimeout(() => {\n update().catch(() => undefined);\n }, state.wait);\n state.wait = Math.min(state.wait * 2, RETRY_MAX_MS);\n\n return;\n }\n state.wait = RETRY_FIRST_MS;\n state.flows = answer.street;\n state.grid = {\n width: sides,\n height: sides,\n bounds: [longitude(bounds[0]), latitude(bounds[3]), longitude(bounds[2]), latitude(bounds[1])],\n };\n send();\n first.resolve?.();\n };\n\n renderer.catch(() => undefined);\n context.layers.push(layer);\n context.followView(layer, update, requests, () => undefined);\n context.stopWith(layer, () => {\n clearTimeout(state.retry);\n });\n\n return Object.assign(layer, {\n computed,\n setWind: (wind: [u: number, v: number]) => {\n state.wind = wind;\n layer.setWeights(wind);\n },\n });\n};\n"]}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
/** The trees of a vector basemap (`VectorTiles.trees`): 3D models scattered by the workers over its woods and grass */
|
|
2
2
|
import type { Layer, ModelLayer } from '../../layers/layers.ts';
|
|
3
|
-
import type { GeoMap } from '../../map.ts';
|
|
4
3
|
import { type TreeColors } from '../trees.ts';
|
|
5
4
|
import type { StyleLayer } from '../vectorstyle.ts';
|
|
6
5
|
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
6
|
/** The options of `VectorTiles.trees` */
|
|
10
7
|
export interface TreesOptions {
|
|
11
8
|
layers?: (layer: StyleLayer) => boolean;
|
|
@@ -19,10 +16,6 @@ export interface TreesOptions {
|
|
|
19
16
|
data?: ArrayBuffer | ArrayBufferView<ArrayBuffer>;
|
|
20
17
|
before?: Layer;
|
|
21
18
|
}
|
|
22
|
-
/** The
|
|
23
|
-
*
|
|
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);
|
|
19
|
+
/** The trees' layers: broadleaved in full (the one returned, holding the others), conifers, then both simplified far
|
|
20
|
+
* away; with a model of the page's (`url`, `data`), that one alone, every tree in full */
|
|
28
21
|
export declare const trees: (context: VectorTilesContext, options?: TreesOptions) => ModelLayer;
|