isard 1.15.0 → 2.0.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +4 -4
  3. package/dist/basemap/vectortiles/placed.js +7 -4
  4. package/dist/basemap/vectortiles/placed.js.map +1 -1
  5. package/dist/basemap/vectortiles/tiles.d.ts +1 -1
  6. package/dist/basemap/vectortiles/tiles.js.map +1 -1
  7. package/dist/basemap/workerpool.d.ts +1 -1
  8. package/dist/basemap/workerpool.js.map +1 -1
  9. package/dist/bind/layers.js +3 -1
  10. package/dist/bind/layers.js.map +1 -1
  11. package/dist/decoder.worker.js +4 -5
  12. package/dist/decoder.worker.js.map +6 -6
  13. package/dist/decoding/decoders.d.ts +1 -1
  14. package/dist/decoding/decoders.js.map +1 -1
  15. package/dist/decoding/loader.d.ts +6 -3
  16. package/dist/decoding/loader.js +7 -5
  17. package/dist/decoding/loader.js.map +1 -1
  18. package/dist/decoding/protocol.d.ts +3 -2
  19. package/dist/decoding/protocol.js.map +1 -1
  20. package/dist/engine-loader.d.ts +20 -18
  21. package/dist/engine-loader.js +45 -42
  22. package/dist/engine-loader.js.map +1 -1
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/isard_tess_bg.wasm +0 -0
  26. package/dist/isard_tiles3d_bg.wasm +0 -0
  27. package/dist/isard_webgl2_bg.wasm +0 -0
  28. package/dist/isard_webgpu_bg.wasm +0 -0
  29. package/dist/layers/custom.d.ts +35 -29
  30. package/dist/layers/custom.js +60 -46
  31. package/dist/layers/custom.js.map +1 -1
  32. package/dist/layers/extrusions.js.map +1 -1
  33. package/dist/layers/features.js.map +1 -1
  34. package/dist/layers/flow.js.map +1 -1
  35. package/dist/layers/glyphs.d.ts +1 -1
  36. package/dist/layers/glyphs.js.map +1 -1
  37. package/dist/layers/ground.d.ts +20 -13
  38. package/dist/layers/ground.js +29 -8
  39. package/dist/layers/ground.js.map +1 -1
  40. package/dist/layers/icons.d.ts +1 -1
  41. package/dist/layers/icons.js.map +1 -1
  42. package/dist/layers/layers.d.ts +1 -2
  43. package/dist/layers/layers.js +2 -11
  44. package/dist/layers/layers.js.map +1 -1
  45. package/dist/layers/models.js +0 -4
  46. package/dist/layers/models.js.map +1 -1
  47. package/dist/layers/network.d.ts +1 -1
  48. package/dist/layers/network.js.map +1 -1
  49. package/dist/layers/panoramas.d.ts +1 -0
  50. package/dist/layers/panoramas.js +3 -2
  51. package/dist/layers/panoramas.js.map +1 -1
  52. package/dist/layers/pointclouds.d.ts +1 -1
  53. package/dist/layers/pointclouds.js +0 -4
  54. package/dist/layers/pointclouds.js.map +1 -1
  55. package/dist/layers/raster.js +2 -2
  56. package/dist/layers/raster.js.map +1 -1
  57. package/dist/layers/symbols.js.map +1 -1
  58. package/dist/layers/tiles3d.d.ts +6 -2
  59. package/dist/layers/tiles3d.js +23 -5
  60. package/dist/layers/tiles3d.js.map +1 -1
  61. package/dist/layers/vectors.d.ts +4 -5
  62. package/dist/layers/vectors.js +7 -15
  63. package/dist/layers/vectors.js.map +1 -1
  64. package/dist/map/engine-settings.d.ts +1 -1
  65. package/dist/map/engine-settings.js.map +1 -1
  66. package/dist/map/engines.d.ts +11 -26
  67. package/dist/map/engines.js +10 -48
  68. package/dist/map/engines.js.map +1 -1
  69. package/dist/map/frame-loop.d.ts +1 -3
  70. package/dist/map/frame-loop.js +3 -3
  71. package/dist/map/frame-loop.js.map +1 -1
  72. package/dist/map/hover-pick.d.ts +9 -3
  73. package/dist/map/hover-pick.js +29 -6
  74. package/dist/map/hover-pick.js.map +1 -1
  75. package/dist/map/layer-stack.d.ts +2 -2
  76. package/dist/map/layer-stack.js +1 -3
  77. package/dist/map/layer-stack.js.map +1 -1
  78. package/dist/map/symbol-atlases.d.ts +5 -4
  79. package/dist/map/symbol-atlases.js +8 -13
  80. package/dist/map/symbol-atlases.js.map +1 -1
  81. package/dist/map/viewshed.d.ts +1 -1
  82. package/dist/map/viewshed.js.map +1 -1
  83. package/dist/map.d.ts +26 -20
  84. package/dist/map.js +97 -82
  85. package/dist/map.js.map +1 -1
  86. package/dist/react/IsardMap.d.ts +1 -1
  87. package/dist/react/IsardMap.js.map +1 -1
  88. package/dist/react/index.d.ts +1 -1
  89. package/dist/react/index.js.map +1 -1
  90. package/dist/types.d.ts +49 -18
  91. package/dist/types.js.map +1 -1
  92. package/dist/ui/interaction.d.ts +1 -1
  93. package/dist/ui/interaction.js.map +1 -1
  94. package/dist/util/animation.d.ts +1 -1
  95. package/dist/util/animation.js.map +1 -1
  96. package/dist/wasm/isard_tiles3d.d.ts +181 -0
  97. package/dist/wasm/isard_tiles3d.js +387 -0
  98. package/dist/wasm/{isard_core.d.ts → isard_webgl2.d.ts} +375 -184
  99. package/dist/wasm/{isard_core.js → isard_webgl2.js} +2167 -415
  100. package/dist/wasm/{isard.d.ts → isard_webgpu.d.ts} +183 -355
  101. package/dist/wasm/{isard.js → isard_webgpu.js} +1374 -1097
  102. package/package.json +4 -3
  103. package/vite.js +5 -4
  104. package/dist/isard_bg.wasm +0 -0
  105. package/dist/isard_core_bg.wasm +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,76 @@ versions [Semantic Versioning](https://semver.org) (before 1.0.0, a minor versio
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [2.0.0] - 2026-10-30
9
+
10
+ With `isard-react-native` and `isard-map` (Python) 2.0.0: the three now share their version.
11
+
12
+ The engine on WebGPU (#146), with breaking changes. From 1.x:
13
+
14
+ - `await` the answers of `map.pick` and `map.pickFeature` (a Promise now).
15
+ - Remove the options `tiles3d`, `wasmUrl` and `coreWasmUrl`; give the engine's files, if you serve them yourself, with
16
+ `webgpuWasmUrl` and `webgl2WasmUrl`.
17
+ - Serve the new files (`isard_webgpu_bg.wasm`, `isard_webgl2_bg.wasm`, `isard_tiles3d_bg.wasm`) in place of
18
+ `isard_bg.wasm` and `isard_core_bg.wasm` (`isard/vite` copies them).
19
+ - Rewrite custom layers for WebGPU: `onAdd(device, map)`, `render(device, frame)`, `onRemove(device, map)`, drawing
20
+ into `frame.color` (and `frame.depth`); see the guide's Custom layers page.
21
+ - `map.surfaceAt` may answer undefined at first: the height is measured a frame or two later.
22
+
23
+ ### Added
24
+
25
+ - Profiling: `bun run profile` plays camera moves on a page (an example, or any page using isard) and gives per move the
26
+ frames, the draw calls and state changes a frame, the engine's CPU time and its GPU time, in all and by layer.
27
+ `map.setGpuTiming(true)` and `map.gpuTimings()` time a frame's parts on the GPU with an engine built to profile
28
+ (`PROFILE=1 bun run build`: timer queries, the functions' names kept); the engines published are unchanged.
29
+
30
+ ### Changed
31
+
32
+ - The engine on wgpu (#146): the map draws through WebGPU, or through wgpu's WebGL2 fallback where a browser has no
33
+ WebGPU (`isard_webgpu_bg.wasm`, `isard_webgl2_bg.wasm`, the 3D Tiles module `isard_tiles3d_bg.wasm` for the workers),
34
+ in place of the WebGL2 engine (`isard_bg.wasm`, `isard_core_bg.wasm` gone, from the package's files and exports and
35
+ from `isard/vite` too). Its shaders in WGSL; the same layers, passes and picking. Measured on a Mac: as fast or
36
+ faster on every example (a region's network zooming out at 59 fps where the WebGL2 engine did 36).
37
+ - `map.pick` and `map.pickFeature` answer with a Promise, a frame or two later: the picking pass's pixels are read back
38
+ once the GPU is done (WebGPU reads nothing back at once), the main thread no longer waiting for it (#146).
39
+ - One engine, 3D Tiles, models, point clouds and panoramas included from the start, through WebGPU or its WebGL2
40
+ fallback (#146): the map no longer moves onto an engine with 3D Tiles for its first 3D layer. The options
41
+ `tiles3d`, `wasmUrl` and `coreWasmUrl` are gone (`webgpuWasmUrl` and `webgl2WasmUrl` for the engine's files).
42
+ - Custom layers draw with WebGPU (#146): `onAdd(device, map)`, `render(device, frame)` and `onRemove(device, map)` get the
43
+ map's `GPUDevice`; `render` draws into the layer's targets (`frame.color`, and `frame.depth` in the '3d' mode, the
44
+ scene's depth to test against), laid over the frame at the layer's place; `frame.matrixAt` is in WebGPU's clip depth.
45
+ On the WebGL2 fallback, custom layers are not drawn. The three.js example on three's WebGPU renderer.
46
+ - `map.surfaceAt` answers undefined until the position is measured: the scene is drawn looking down at it after a
47
+ frame and read back a frame or two later, the answer kept and measured again every 250 ms at most (#146).
48
+ `map.pickSurface` answers at once from the last copy of the scene's depth, a frame or two old, without waiting for the
49
+ GPU.
50
+
51
+ ### Fixed
52
+
53
+ - The trees and street furniture placed over a vector basemap are the same whether the relief under the view's center
54
+ came before or after them (chosen from the camera's scale, not the ground's).
55
+
56
+ ## [1.16.0] - 2026-10-29
57
+
58
+ With `isard-react-native` 0.5.0 and `isard-map` 0.5.0 (Python).
59
+
60
+ ### Added
61
+
62
+ - Rasters draped on the 3D Tiles: `drape: { raster, faces, opacity }` in `addTiles3d` (or `setDrape`) lays a raster
63
+ layer on the meshes' roofs, or all their faces, as Cesium's imagery on 3D Tiles (an ortho on the untextured
64
+ buildings, a solar potential on the roofs); `ground: false` on a raster keeps it off the ground, its tiles loaded for
65
+ the 3D layers it is draped on. The An ortho on the roofs example (TypeScript, React, Python, React Native).
66
+ - `antialias` (`GeoMapOptions`, default true): `false` draws the canvas without multisampling, as MapLibre does. On an
67
+ integrated GPU, a network's wide halo over a region costs up to four times less.
68
+ - The benchmark's camera moves against MapLibre (`/bench/?scenario=moves`, `bun run perf moves`).
69
+
70
+ ### Performance
71
+
72
+ - Camera moves over a large network (issue #138, geo-reach: the network of Île-de-France and its halo, an Intel UHD):
73
+ from 21 fps (95th percentile 133 ms, frames up to 433 ms) to 56 – 57 fps (worst frame 50 ms) with `antialias: false`.
74
+ A network's halo works out its values at its vertices, interpolated, rather than at each of its pixels (the lines
75
+ keep theirs, where two fronts meet), and is drawn at half the resolution then laid over the frame (without relief
76
+ nor swipe; its blur hides the coarser grid): a quarter of its pixels to blend.
77
+
8
78
  ## [1.15.0] - 2026-10-29
9
79
 
10
80
  With `isard-react-native` 0.4.0 and `isard-map` 0.4.0 (Python).
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  **Maps that recolor at every mouse move.**
8
8
 
9
- A WebGL2 map engine for large, interactive data layers, labels and 3D Tiles.<br />
9
+ A WebGPU map engine (WebGL2 where a browser has no WebGPU) for large, interactive data layers, labels and 3D Tiles.<br />
10
10
  Rust core in WebAssembly, a small TypeScript API.
11
11
 
12
12
  [![npm](https://img.shields.io/npm/v/isard?color=2f6fd1)](https://www.npmjs.com/package/isard)
@@ -51,7 +51,7 @@ General-purpose map libraries spend their time on things these maps do not need.
51
51
  models in 3D Tiles (Draco, meshopt, KTX2).
52
52
  - ☁️ **Point clouds.** LiDAR in COPC read by range requests (the IGN's LiDAR HD, reprojected from Lambert-93 onto the
53
53
  relief), 3D Tiles points; colored by RGB, class, altitude or intensity, Eye-Dome Lighting, a point budget, picked.
54
- - 🧊 **Your own 3D.** glTF models at positions, instanced and picked; custom layers for your WebGL code or a three.js
54
+ - 🧊 **Your own 3D.** glTF models at positions, instanced and picked; custom layers for your WebGPU code or a three.js
55
55
  scene, in the map's frame and depth, with camera-relative matrices exact at any zoom.
56
56
  - 🦀 **Small and exact.** 278 KB of WebAssembly gzipped (452 KB once a 3D Tiles layer, a model or a point cloud is added), f64 on the CPU and f32 relative to the camera on the GPU
57
57
  (centimetres at any zoom), frames on demand only, strict TypeScript types end to end.
@@ -126,7 +126,7 @@ Live in the [documentation](https://ideal-adventure-zqn6y6p.pages.github.io/exam
126
126
  | [glTF models](https://ideal-adventure-zqn6y6p.pages.github.io/layers/models) | `addModels` | a glTF model at many positions, instanced, on the relief, picked |
127
127
  | [Point clouds](https://ideal-adventure-zqn6y6p.pages.github.io/layers/pointclouds) | `addPointCloud` | COPC (LiDAR HD) by range requests, pnts and glTF points; by class, altitude, intensity, EDL |
128
128
  | [Flows](https://ideal-adventure-zqn6y6p.pages.github.io/layers/flows) | `addFlow`, `readGrids` | particles carried by a wind or a current, a model's hours along a clock, its GRIB2 and NetCDF files read in workers, the wind through a city's streets (`streetWind`) |
129
- | [Custom layers](https://ideal-adventure-zqn6y6p.pages.github.io/layers/custom) | `addCustomLayer` | your WebGL code or a three.js scene in the map's frame, sharing its depth |
129
+ | [Custom layers](https://ideal-adventure-zqn6y6p.pages.github.io/layers/custom) | `addCustomLayer` | your WebGPU code or a three.js scene in the map's frame, tested against its depth |
130
130
 
131
131
  Plus markers, popups, controls, picking within a radius, `easeTo`, `flyTo`, a sky and fog for tilted views. All in
132
132
  the [API reference](https://ideal-adventure-zqn6y6p.pages.github.io/api).
@@ -167,7 +167,7 @@ drives both. Each crate has its README; [crates/README.md](crates/README.md) gui
167
167
  crates/geo/ camera, projections, geodesy and geoid, tile selection, label placement, polygons tested natively
168
168
  crates/tiles3d/ 3D Tiles tree, traversal and decoding tested natively
169
169
  crates/pointcloud/ COPC point clouds: header, octree hierarchy, traversal, LAZ chunks tested natively
170
- crates/engine/ the WebAssembly core: the engine, the ground, the layers, picking
170
+ crates/engine-wgpu/ the WebAssembly engine on wgpu (WebGPU, or its WebGL2 fallback): the ground, the layers, picking
171
171
  crates/tess/ the tessellation module: vector tiles made ready for the GPU in the basemap workers
172
172
  crates/grid/ the grid module: GRIB2 and NetCDF files read into grids, the wind through the streets tested natively
173
173
  packages/isard/ the npm package isard: GeoMap, layer handles, overlays, workers
@@ -3,7 +3,7 @@
3
3
  * each kind one instanced model layer: all of them near the ground under the camera, fewer and fewer past it (a
4
4
  * simplified model there when the kind has one), the tiles following the view.
5
5
  */
6
- import { METRES_PER_DEGREE, RAD } from "../../util/geo.js";
6
+ import { EARTH_METRES, METRES_PER_DEGREE, RAD } from "../../util/geo.js";
7
7
  import { PLACED_KIND, PLACED_NUMBERS, PLACED_RANK } from "../placed.js";
8
8
  import { TileRequests } from "./requests.js";
9
9
  import { nearPriority, tileKey, tilesAround } from "./tiles.js";
@@ -13,10 +13,13 @@ const FOV = 0.6435011087932844;
13
13
  * zoomed as much): going through the tiles' things at every frame of a drag would hold the main thread */
14
14
  const RESEND_SHARE = 0.05;
15
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) */
16
+ * stands behind the center of a tilted view, `FOV` its field of view). The camera's own scale at the center (512
17
+ * pixels a tile), not the ground's under it (`metersPerPixel`): the things chosen the same before and after the relief
18
+ * there has come */
17
19
  const groundUnderCamera = (map) => {
18
- const { pitch, bearing } = map.getCamera();
19
- const back = ((0.5 * map.getCanvas().clientHeight) / Math.tan(FOV / 2)) * Math.sin(pitch * RAD) * (map.metersPerPixel() ?? 0);
20
+ const { center, zoom, pitch, bearing } = map.getCamera();
21
+ const metresPerPixel = (EARTH_METRES * Math.cos(center[1] * RAD)) / (512 * 2 ** zoom);
22
+ const back = ((0.5 * map.getCanvas().clientHeight) / Math.tan(FOV / 2)) * Math.sin(pitch * RAD) * metresPerPixel;
20
23
  return [-back * Math.sin(bearing * RAD), -back * Math.cos(bearing * RAD), back];
21
24
  };
22
25
  /** What follows the camera as it moves: `send` called again once it has gone `RESEND_SHARE` of `radius` metres (or
@@ -1 +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 } from '../../layers/layers.ts';\nimport type { ModelLayer, ModelOptions } from '../../layers/models.ts';\nimport type { GeoMap } from '../../map.ts';\nimport { METRES_PER_DEGREE, RAD } from '../../util/geo.ts';\nimport type { BasemapResponse, BasemapWork, Priority } from '../../workers/basemap/protocol.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)) * Math.sin(pitch * RAD) * (map.metersPerPixel() ?? 0);\n\n return [-back * Math.sin(bearing * RAD), -back * Math.cos(bearing * RAD), 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] = [center[0] * METRES_PER_DEGREE * Math.cos(center[1] * RAD), center[1] * METRES_PER_DEGREE];\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] * RAD);\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
+ {"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 } from '../../layers/layers.ts';\nimport type { ModelLayer, ModelOptions } from '../../layers/models.ts';\nimport type { GeoMap } from '../../map.ts';\nimport { EARTH_METRES, METRES_PER_DEGREE, RAD } from '../../util/geo.ts';\nimport type { BasemapResponse, BasemapWork, Priority } from '../../workers/basemap/protocol.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). The camera's own scale at the center (512\n * pixels a tile), not the ground's under it (`metersPerPixel`): the things chosen the same before and after the relief\n * there has come */\nconst groundUnderCamera = (map: GeoMap): [east: number, north: number, distance: number] => {\n const { center, zoom, pitch, bearing } = map.getCamera();\n const metresPerPixel = (EARTH_METRES * Math.cos(center[1] * RAD)) / (512 * 2 ** zoom);\n const back = ((0.5 * map.getCanvas().clientHeight) / Math.tan(FOV / 2)) * Math.sin(pitch * RAD) * metresPerPixel;\n\n return [-back * Math.sin(bearing * RAD), -back * Math.cos(bearing * RAD), 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] = [center[0] * METRES_PER_DEGREE * Math.cos(center[1] * RAD), center[1] * METRES_PER_DEGREE];\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] * RAD);\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"]}
@@ -3,7 +3,7 @@
3
3
  * for in, and the defaults the layers share.
4
4
  */
5
5
  import type { GeoMap } from '../../map.ts';
6
- import type { Camera } from '../../wasm/isard.js';
6
+ import type { Camera } from '../../wasm/isard_webgpu.js';
7
7
  import type { Priority } from '../../workers/basemap/protocol.ts';
8
8
  /** A tile: its level and its column and row at that level */
9
9
  export type TileTriple = [z: number, x: number, y: number];
@@ -1 +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/protocol.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) */\nconst 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"]}
1
+ {"version":3,"file":"tiles.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/tiles.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAOzD,iGAAiG;AACjG,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAE9B,wFAAwF;AACxF,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC;AAE5B,wGAAwG;AACxG,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB,sFAAsF;AACtF,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,4BAA4B;AAC5B,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAErF,iEAAiE;AACjE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAc,EAAE;IACtD,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEzD,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACnB,CAAC,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAiB,EAAgB,EAAE,CAC7D,KAAK,CAAC,IAAI,CACR,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,EACvC,CAAC,CAAC,EAAE,CAAC,EAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CACrF,CAAC;AAEJ,sHAAsH;AACtH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,OAAiB,MAAM,EAAE,MAAgB,KAAK,EAAY,EAAE,CACtG,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AAElC;WACW;AACX,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE;IACzD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEjB,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,MAAc,EAAE,CAAS,EAAE,QAAgB,EAA4B,EAAE;IAChH,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjB,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;IACnD,MAAM,EAAE,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3D,MAAM,EAAE,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3D,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACpF,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChG,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IACtH,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9F,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAoB,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAC1F,CAAC;IAEF,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;IAEnH,2EAA2E;IAC3E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,OAAO,MAAM;SACV,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAoB,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SACxD,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;QACjB,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAEtB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAEZ,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AACxB,CAAC,CAAC","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_webgpu.js';\nimport type { Priority } from '../../workers/basemap/protocol.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) */\nconst 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"]}
@@ -1,6 +1,6 @@
1
1
  /** The pool of basemap workers the vector tiles share: a vector tile always goes to the same worker (its decoded copy
2
2
  * kept there), the requests of an owner cancelled together, the renderers broadcast to every worker */
3
- import type { Camera } from '../wasm/isard.js';
3
+ import type { Camera } from '../wasm/isard_webgpu.js';
4
4
  import type { Priority } from '../workers/basemap/protocol.ts';
5
5
  /** Default size of a basemap worker pool: cores - 1, 1 to `most` (4 by default, fewer at a lower quality) */
6
6
  export declare const defaultWorkerCount: (most?: number) => number;
@@ -1 +1 @@
1
- {"version":3,"file":"workerpool.js","sourceRoot":"","sources":["../../src/basemap/workerpool.ts"],"names":[],"mappings":"AAAA;uGACuG;AAEvG,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGjE,OAAO,EAAY,YAAY,EAAE,MAAM,eAAe,CAAC;AAGvD,6GAA6G;AAC7G,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAI,GAAG,CAAC,EAAU,EAAE;IACrD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,SAAS,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtH,CAAC,CAAC;AAEF,6GAA6G;AAC7G,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAwB,EAAgB,EAAE;IACzE,OAAO,QAAQ,CAAC,mBAAmB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AAC7D,CAAC,CAAC;AAEF;oEACoE;AACpE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,MAAuC,EAAY,EAAE;IACjH,wDAAwD;IACxD,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAE1C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjB,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC9B,yCAAyC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IACtC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;IAEvC,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,MAAM,CAAC;IAE5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACjC,CAAC,CAAC;AAEF,qEAAqE;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,KAAa,EAAU,EAAE;IACvF,wCAAwC;IACxC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC/F,CAAC,CAAC;AAEF,wFAAwF;AACxF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,SAAiB,EAAE,CAAS,EAAU,EAAE;IAClE,OAAO,GAAG,SAAS,KAAK,CAAC,EAAE,CAAC;AAC9B,CAAC,CAAC;AAKF;;;;GAIG;AACH,MAAM,OAAO,cAAc;IAmBd;IACA;IAnBM,OAAO,CAAgC;IACvC,OAAO,GAAG,IAAI,GAAG,EAG/B,CAAC;IACI,IAAI,GAAG,CAAC,CAAC;IACjB;0CACsC;IACrB,QAAQ,GAAG,IAAI,OAAO,EAAc,CAAC;IACrC,IAAI,GAAG,IAAI,GAAG,EAAqB,CAAC;IACrD,yDAAyD;IACjD,IAAI,GAAG,CAAC,CAAC;IACT,UAAU,GAAG,CAAC,CAAC;IACf,UAAU,GAAG,KAAK,CAAC;IAC3B,iDAAiD;IAChC,QAAQ,CAAa;IAEtC,YACW,KAAa,EACb,GAAiB,EAC1B,SAA4C,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAF3E,UAAK,GAAL,KAAK,CAAQ;QACb,QAAG,GAAH,GAAG,CAAc;QAG1B,MAAM,KAAK,GAAG,GAAe,EAAE;YAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAE3B,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,IAAI,EAAiC,EAAE,EAAE;gBAC7D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAE1B,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAEpC,IAAI,CAAC,CAAC;oBAAE,OAAO;gBACf,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC7B,IAAI,OAAO,IAAI,IAAI;oBAAE,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;;oBAChD,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACvB,CAAC,CAAC;YACF,iHAAiH;YACjH,0GAA0G;YAC1G,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;gBACzB,KAAK,CAAC,cAAc,EAAE,CAAC;gBAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CACrB,MAAM,EACN,6BAA6B,GAAG,UAAU,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACtF,CAAC;gBAEF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;oBAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC/D,CAAC,CAAC;YACF,MAAM,CAAC,cAAc,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,6BAA6B,GAAG,6BAA6B,CAAC,CAAC;YAE/G,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;YAE5B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAA2B,CAAC,CAAC;YAE9F,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEF,IAAI,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;QACnF,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC,CAAC,KAAK,EAAE,EAAE;YACtC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;gBACzB,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAA2B,CAAC,CAAC;YACrE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,0DAA0D;IAC1D,SAAS;QACP,OAAO,IAAI,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;IACjC,CAAC;IAED,2BAA2B;IAC3B,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,uEAAuE;IAC/D,IAAI,CAAC,MAAkB,EAAE,OAAe;QAC9C,MAAM,KAAK,GAAG,IAAI,KAAK,CACrB,UAAU,OAAO,sHAAsH,CACxI,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;YAC7B,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;gBAAE,OAAO;YAChC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0FAA0F;IAC1F,MAAM,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU;QACvC,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,6FAA6F;IACrF,MAAM,CAAC,KAAa;QAC1B,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QACzB,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9E,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7D,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAED,wGAAwG;IACxG,SAAS,CAAC,OAAwF;QAChG,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAE5B,uFAAuF;QACvF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAE9F,6DAA6D;QAC7D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACzB,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,uEAAuE;IACvE,OAAO,CAAC,MAAkB,EAAE,IAAiB,EAAE,KAAa,EAAE,MAAoB;QAChF,OAAO,IAAI,OAAO,CAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACtD,IAAI,IAAI,CAAC,UAAU;gBAAE,OAAO,MAAM,CAAC,IAAI,YAAY,CAAC,+BAA+B,EAAE,YAAY,CAAC,CAAC,CAAC;YACpG,IAAI,MAAM,EAAE,OAAO;gBAAE,OAAO,MAAM,CAAC,IAAI,YAAY,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC,CAAC;YAErF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAEnC,IAAI,IAAI;gBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;YAE9B,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,GAAG,EAAE;gBACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;oBAAE,OAAO;gBACrC,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAA2B,CAAC,CAAC;gBACnE,MAAM,CAAC,IAAI,YAAY,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC,CAAC;YAC3D,CAAC,CAAC;YACF,gDAAgD;YAChD,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAEjE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBACnB,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;oBACb,MAAM,EAAE,CAAC;oBACT,OAAO,CAAC,CAAC,CAAC,CAAC;gBACb,CAAC;gBACD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;oBACZ,MAAM,EAAE,CAAC;oBACT,MAAM,CAAC,CAAC,CAAC,CAAC;gBACZ,CAAC;gBACD,MAAM;gBACN,KAAK;aACN,CAAC,CAAC;YACH,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACzD,MAAM,CAAC,WAAW,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,EAA2B,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,wGAAwG;IACxG,OAAO,CACL,GAAW,EACX,QAAqB,EACrB,KAAyB,EACzB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAA2B,EACnC,MAAmB,EACnB,KAAa;QAEb,MAAM,IAAI,GAAgB,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAExG,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClH,CAAC;IAED,6GAA6G;IAC7G,SAAS,CACP,GAAQ,EACR,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAA2B,EACnC,MAAmB,EACnB,KAAa;QAEb,mHAAmH;QACnH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3E,MAAM,IAAI,GAAgB,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;QAE7D,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAChG,CAAC;IAED;+CAC2C;IAC3C,KAAK,CACH,MAAgD,EAChD,MAAc,EACd,MAA+B,EAC/B,KAAa;QAEb,MAAM,IAAI,GAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QAE/D,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QAElD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC1E,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAChF,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,MAAM,CAAC,KAAa;QAClB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;YAC7B,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK;gBAAE,OAAO;YAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAA2B,CAAC,CAAC;YACrE,CAAC,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,+BAA+B,EAAE,YAAY,CAAC,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;IACL,CAAC;IAED,6CAA6C;IAC7C,SAAS;QACP,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACzB,CAAC,CAAC,SAAS,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAE3C,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACpB,CAAC,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,+BAA+B,EAAE,YAAY,CAAC,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["/** The pool of basemap workers the vector tiles share: a vector tile always goes to the same worker (its decoded copy\n * kept there), the requests of an owner cancelled together, the renderers broadcast to every worker */\n\nimport { assetUrl } from '../engine-loader.ts';\nimport type { GridDescription } from '../grid-module.ts';\nimport { mercatorX, mercatorY } from '../util/geo.ts';\nimport { headerRules, onHeaderRules } from '../util/requests.ts';\nimport type { Camera } from '../wasm/isard.js';\nimport type { BasemapRequest, BasemapResponse, BasemapWork, Priority } from '../workers/basemap/protocol.ts';\nimport { type Job, SOURCE_CACHE } from './resample.ts';\nimport type { PngEncoding } from './terrain.ts';\n\n/** Default size of a basemap worker pool: cores - 1, 1 to `most` (4 by default, fewer at a lower quality) */\nexport const defaultWorkerCount = (most = 4): number => {\n return Math.min(most, Math.max(1, (typeof navigator !== 'undefined' ? navigator.hardwareConcurrency || 2 : 2) - 1));\n};\n\n/** Default URL of the basemap worker: in the page's assets folder (`isard/vite`), else next to the module */\nexport const defaultWorkerUrl = (assetsUrl?: string | URL): string | URL => {\n return assetUrl('basemap.worker.js', undefined, assetsUrl);\n};\n\n/** Fetch priority of a raster tile drawn by the workers: 'high' near the center of the view, at the current zoom or\n * coarser; 'low' far from it or finer (prefetch); 'auto' between */\nexport const tilePriority = (z: number, x: number, y: number, camera: Pick<Camera, 'center' | 'zoom'>): Priority => {\n // A raster tile of level z covers the map at zoom z - 1\n if (z - 1 > camera.zoom + 1) return 'low';\n\n const n = 2 ** z;\n const [lon, lat] = camera.center;\n const cx = mercatorX(lon) * n;\n const cy = mercatorY(lat) * n;\n // Across the antimeridian, the short way\n const along = Math.abs(x + 0.5 - cx) % n;\n const dx = Math.min(along, n - along);\n const d = Math.hypot(dx, y + 0.5 - cy);\n\n if (d <= 1.5) return 'high';\n\n return d >= 4 ? 'low' : 'auto';\n};\n\n/** The worker of a vector tile among `count`: always the same one */\nexport const workerIndex = (vz: number, vx: number, vy: number, count: number): number => {\n // Unsigned: every worker gets its share\n return ((Math.imul(vx, 73856093) ^ Math.imul(vy, 19349663) ^ vz) >>> 0) % Math.max(1, count);\n};\n\n/** The worker-side key of a renderer: unique across the `VectorTiles` sharing a pool */\nexport const rendererKey = (namespace: string, n: number): string => {\n return `${namespace}:r${n}`;\n};\n\n/** What the pool needs of a worker (a `Worker`, or a stand-in in tests) */\nexport type PoolWorker = Pick<Worker, 'postMessage' | 'terminate' | 'onmessage' | 'onerror' | 'onmessageerror'>;\n\n/**\n * @internal Workers drawing vector tiles, shared by the `VectorTiles` of a map: each vector tile always goes to the\n * same worker, which keeps it decoded for every style drawn from it. Requests are tracked one by one, with their\n * owner, so that one `VectorTiles` going away cancels its own requests only.\n */\nexport class BasemapWorkers {\n private readonly workers: [PoolWorker, ...PoolWorker[]];\n private readonly pending = new Map<\n number,\n { resolve: (r: BasemapResponse) => void; reject: (e: Error) => void; worker: PoolWorker; owner: object }\n >();\n private next = 1;\n /** The workers that answered once (they loaded), and those that failed before: dead, their error given at once to\n * any request still sent their way */\n private readonly answered = new WeakSet<PoolWorker>();\n private readonly dead = new Map<PoolWorker, Error>();\n /** The worker the next file of grids goes to, in turn */\n private turn = 0;\n private namespaces = 0;\n private terminated = false;\n /** Stops following the page's request headers */\n private readonly unfollow: () => void;\n\n constructor(\n readonly count: number,\n readonly url: string | URL,\n create: (url: string | URL) => PoolWorker = (u) => new Worker(u, { type: 'module' }),\n ) {\n const start = (): PoolWorker => {\n const worker = create(url);\n\n worker.onmessage = ({ data }: MessageEvent<BasemapResponse>) => {\n this.answered.add(worker);\n\n const p = this.pending.get(data.id);\n\n if (!p) return;\n this.pending.delete(data.id);\n if ('error' in data) p.reject(new Error(data.error));\n else p.resolve(data);\n };\n // A worker that fails to load (a bundler serving it from elsewhere) or to read a message fails its requests; one\n // that never answered is dead: its tiles go to the others, and with none left every request fails at once\n worker.onerror = (event) => {\n event.preventDefault();\n\n const error = this.fail(\n worker,\n `the vector basemap worker ${url} failed${event.message ? `: ${event.message}` : ''}`,\n );\n\n if (!this.answered.has(worker)) this.dead.set(worker, error);\n };\n worker.onmessageerror = () => this.fail(worker, `the vector basemap worker ${url} sent an unreadable message`);\n\n const rules = headerRules();\n\n if (rules.length > 0) worker.postMessage({ type: 'headers', rules } satisfies BasemapRequest);\n\n return worker;\n };\n\n this.workers = [start(), ...Array.from({ length: Math.max(1, count) - 1 }, start)];\n this.unfollow = onHeaderRules((rules) => {\n this.workers.forEach((w) => {\n w.postMessage({ type: 'headers', rules } satisfies BasemapRequest);\n });\n });\n }\n\n /** A prefix for the renderer keys of one `VectorTiles` */\n namespace(): string {\n return `v${this.namespaces++}`;\n }\n\n /** Requests in progress */\n get size(): number {\n return this.pending.size;\n }\n\n /** Rejects the requests of a failed worker, with the error returned */\n private fail(worker: PoolWorker, message: string): Error {\n const error = new Error(\n `isard: ${message}. If a bundler moves the worker, give its URL in the \\`basemapWorkerUrl\\` option (see \"With a bundler\" in the guide)`,\n );\n\n this.pending.forEach((p, id) => {\n if (p.worker !== worker) return;\n this.pending.delete(id);\n p.reject(error);\n });\n\n return error;\n }\n\n /** The worker of a vector tile: always the same one, or the next living one if it died */\n worker(vz: number, vx: number, vy: number): PoolWorker {\n return this.living(workerIndex(vz, vx, vy, this.workers.length));\n }\n\n /** The worker at `index`, or the next one that has not died (the first one when all have) */\n private living(index: number): PoolWorker {\n const { workers } = this;\n const at = (k: number) => workers[(index + k) % workers.length] ?? workers[0];\n const k = workers.findIndex((_, k) => !this.dead.has(at(k)));\n\n return at(Math.max(0, k));\n }\n\n /** Sends a message to every worker (a renderer, or its removal, or where the tessellation module is) */\n broadcast(message: Extract<BasemapRequest, { type: 'init' } | { type: 'drop' } | { type: 'tess' }>): void {\n if (this.terminated) return;\n\n // A renderer tells the workers how many they are: they share the decoded tiles' budget\n const sent = message.type === 'init' ? { ...message, workers: this.workers.length } : message;\n\n // A sprite image is copied to each worker (structured clone)\n this.workers.forEach((w) => {\n w.postMessage(sent);\n });\n }\n\n /** Asks a worker for a tile's image or labels, on behalf of `owner` */\n request(worker: PoolWorker, work: BasemapWork, owner: object, signal?: AbortSignal): Promise<BasemapResponse> {\n return new Promise<BasemapResponse>((resolve, reject) => {\n if (this.terminated) return reject(new DOMException('isard: vector tiles destroyed', 'AbortError'));\n if (signal?.aborted) return reject(new DOMException('isard: aborted', 'AbortError'));\n\n const dead = this.dead.get(worker);\n\n if (dead) return reject(dead);\n\n const id = this.next++;\n const abort = () => {\n if (!this.pending.delete(id)) return;\n worker.postMessage({ type: 'abort', id } satisfies BasemapRequest);\n reject(new DOMException('isard: aborted', 'AbortError'));\n };\n // The listener goes once the request is settled\n const settle = () => signal?.removeEventListener('abort', abort);\n\n this.pending.set(id, {\n resolve: (r) => {\n settle();\n resolve(r);\n },\n reject: (e) => {\n settle();\n reject(e);\n },\n worker,\n owner,\n });\n signal?.addEventListener('abort', abort, { once: true });\n worker.postMessage({ ...work, id } satisfies BasemapRequest);\n });\n }\n\n /** The altitudes of a PNG relief tile `z`/`x`/`y` at `url`, decoded by a worker (see `fetchHeights`) */\n heights(\n url: string,\n encoding: PngEncoding,\n floor: number | undefined,\n [z, x, y]: [number, number, number],\n signal: AbortSignal,\n owner: object,\n ): Promise<Float32Array | null> {\n const work: BasemapWork = { type: 'heights', url, encoding, ...(floor === undefined ? {} : { floor }) };\n\n return this.request(this.worker(z, x, y), work, owner, signal).then((r) => ('heights' in r ? r.heights : null));\n }\n\n /** Mercator tile `z`/`x`/`y` reprojected by a worker from the source images of its plan (see `resampler`) */\n reproject(\n job: Job,\n [z, x, y]: [number, number, number],\n signal: AbortSignal,\n owner: object,\n ): Promise<ImageBitmap | null> {\n // Blocks of 4 × 4 Mercator tiles go to the same worker: neighbours share source tiles, each worker keeps its share\n const worker = this.worker(Math.max(0, z - 2), x >> 2, y >> 2);\n const cached = Math.max(16, Math.ceil(SOURCE_CACHE / this.workers.length));\n const work: BasemapWork = { type: 'reproject', job, cached };\n\n return this.request(worker, work, owner, signal).then((r) => ('image' in r ? r.image : null));\n }\n\n /** A GRIB2 or NetCDF file (its URL, fetched by the worker, or its bytes, transferred) read into grids by the grid\n * module (`module`), in the next worker */\n grids(\n source: { url: string } | { bytes: ArrayBuffer },\n module: string,\n signal: AbortSignal | undefined,\n owner: object,\n ): Promise<{ grids: GridDescription[]; values: Float32Array[] }> {\n const work: BasemapWork = { type: 'grids', module, ...source };\n\n this.turn = (this.turn + 1) % this.workers.length;\n\n return this.request(this.living(this.turn), work, owner, signal).then((r) =>\n 'grids' in r ? { grids: r.grids, values: r.values } : { grids: [], values: [] },\n );\n }\n\n /** Cancels the requests of an owner (the workers stop them) */\n cancel(owner: object): void {\n this.pending.forEach((p, id) => {\n if (p.owner !== owner) return;\n this.pending.delete(id);\n p.worker.postMessage({ type: 'abort', id } satisfies BasemapRequest);\n p.reject(new DOMException('isard: vector tiles destroyed', 'AbortError'));\n });\n }\n\n /** Stops the workers; their requests fail */\n terminate(): void {\n if (this.terminated) return;\n this.terminated = true;\n this.unfollow();\n this.workers.forEach((w) => {\n w.terminate();\n });\n\n const pending = [...this.pending.values()];\n\n this.pending.clear();\n pending.forEach((p) => {\n p.reject(new DOMException('isard: vector tiles destroyed', 'AbortError'));\n });\n }\n}\n"]}
1
+ {"version":3,"file":"workerpool.js","sourceRoot":"","sources":["../../src/basemap/workerpool.ts"],"names":[],"mappings":"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","sourcesContent":["/** The pool of basemap workers the vector tiles share: a vector tile always goes to the same worker (its decoded copy\n * kept there), the requests of an owner cancelled together, the renderers broadcast to every worker */\n\nimport { assetUrl } from '../engine-loader.ts';\nimport type { GridDescription } from '../grid-module.ts';\nimport { mercatorX, mercatorY } from '../util/geo.ts';\nimport { headerRules, onHeaderRules } from '../util/requests.ts';\nimport type { Camera } from '../wasm/isard_webgpu.js';\nimport type { BasemapRequest, BasemapResponse, BasemapWork, Priority } from '../workers/basemap/protocol.ts';\nimport { type Job, SOURCE_CACHE } from './resample.ts';\nimport type { PngEncoding } from './terrain.ts';\n\n/** Default size of a basemap worker pool: cores - 1, 1 to `most` (4 by default, fewer at a lower quality) */\nexport const defaultWorkerCount = (most = 4): number => {\n return Math.min(most, Math.max(1, (typeof navigator !== 'undefined' ? navigator.hardwareConcurrency || 2 : 2) - 1));\n};\n\n/** Default URL of the basemap worker: in the page's assets folder (`isard/vite`), else next to the module */\nexport const defaultWorkerUrl = (assetsUrl?: string | URL): string | URL => {\n return assetUrl('basemap.worker.js', undefined, assetsUrl);\n};\n\n/** Fetch priority of a raster tile drawn by the workers: 'high' near the center of the view, at the current zoom or\n * coarser; 'low' far from it or finer (prefetch); 'auto' between */\nexport const tilePriority = (z: number, x: number, y: number, camera: Pick<Camera, 'center' | 'zoom'>): Priority => {\n // A raster tile of level z covers the map at zoom z - 1\n if (z - 1 > camera.zoom + 1) return 'low';\n\n const n = 2 ** z;\n const [lon, lat] = camera.center;\n const cx = mercatorX(lon) * n;\n const cy = mercatorY(lat) * n;\n // Across the antimeridian, the short way\n const along = Math.abs(x + 0.5 - cx) % n;\n const dx = Math.min(along, n - along);\n const d = Math.hypot(dx, y + 0.5 - cy);\n\n if (d <= 1.5) return 'high';\n\n return d >= 4 ? 'low' : 'auto';\n};\n\n/** The worker of a vector tile among `count`: always the same one */\nexport const workerIndex = (vz: number, vx: number, vy: number, count: number): number => {\n // Unsigned: every worker gets its share\n return ((Math.imul(vx, 73856093) ^ Math.imul(vy, 19349663) ^ vz) >>> 0) % Math.max(1, count);\n};\n\n/** The worker-side key of a renderer: unique across the `VectorTiles` sharing a pool */\nexport const rendererKey = (namespace: string, n: number): string => {\n return `${namespace}:r${n}`;\n};\n\n/** What the pool needs of a worker (a `Worker`, or a stand-in in tests) */\nexport type PoolWorker = Pick<Worker, 'postMessage' | 'terminate' | 'onmessage' | 'onerror' | 'onmessageerror'>;\n\n/**\n * @internal Workers drawing vector tiles, shared by the `VectorTiles` of a map: each vector tile always goes to the\n * same worker, which keeps it decoded for every style drawn from it. Requests are tracked one by one, with their\n * owner, so that one `VectorTiles` going away cancels its own requests only.\n */\nexport class BasemapWorkers {\n private readonly workers: [PoolWorker, ...PoolWorker[]];\n private readonly pending = new Map<\n number,\n { resolve: (r: BasemapResponse) => void; reject: (e: Error) => void; worker: PoolWorker; owner: object }\n >();\n private next = 1;\n /** The workers that answered once (they loaded), and those that failed before: dead, their error given at once to\n * any request still sent their way */\n private readonly answered = new WeakSet<PoolWorker>();\n private readonly dead = new Map<PoolWorker, Error>();\n /** The worker the next file of grids goes to, in turn */\n private turn = 0;\n private namespaces = 0;\n private terminated = false;\n /** Stops following the page's request headers */\n private readonly unfollow: () => void;\n\n constructor(\n readonly count: number,\n readonly url: string | URL,\n create: (url: string | URL) => PoolWorker = (u) => new Worker(u, { type: 'module' }),\n ) {\n const start = (): PoolWorker => {\n const worker = create(url);\n\n worker.onmessage = ({ data }: MessageEvent<BasemapResponse>) => {\n this.answered.add(worker);\n\n const p = this.pending.get(data.id);\n\n if (!p) return;\n this.pending.delete(data.id);\n if ('error' in data) p.reject(new Error(data.error));\n else p.resolve(data);\n };\n // A worker that fails to load (a bundler serving it from elsewhere) or to read a message fails its requests; one\n // that never answered is dead: its tiles go to the others, and with none left every request fails at once\n worker.onerror = (event) => {\n event.preventDefault();\n\n const error = this.fail(\n worker,\n `the vector basemap worker ${url} failed${event.message ? `: ${event.message}` : ''}`,\n );\n\n if (!this.answered.has(worker)) this.dead.set(worker, error);\n };\n worker.onmessageerror = () => this.fail(worker, `the vector basemap worker ${url} sent an unreadable message`);\n\n const rules = headerRules();\n\n if (rules.length > 0) worker.postMessage({ type: 'headers', rules } satisfies BasemapRequest);\n\n return worker;\n };\n\n this.workers = [start(), ...Array.from({ length: Math.max(1, count) - 1 }, start)];\n this.unfollow = onHeaderRules((rules) => {\n this.workers.forEach((w) => {\n w.postMessage({ type: 'headers', rules } satisfies BasemapRequest);\n });\n });\n }\n\n /** A prefix for the renderer keys of one `VectorTiles` */\n namespace(): string {\n return `v${this.namespaces++}`;\n }\n\n /** Requests in progress */\n get size(): number {\n return this.pending.size;\n }\n\n /** Rejects the requests of a failed worker, with the error returned */\n private fail(worker: PoolWorker, message: string): Error {\n const error = new Error(\n `isard: ${message}. If a bundler moves the worker, give its URL in the \\`basemapWorkerUrl\\` option (see \"With a bundler\" in the guide)`,\n );\n\n this.pending.forEach((p, id) => {\n if (p.worker !== worker) return;\n this.pending.delete(id);\n p.reject(error);\n });\n\n return error;\n }\n\n /** The worker of a vector tile: always the same one, or the next living one if it died */\n worker(vz: number, vx: number, vy: number): PoolWorker {\n return this.living(workerIndex(vz, vx, vy, this.workers.length));\n }\n\n /** The worker at `index`, or the next one that has not died (the first one when all have) */\n private living(index: number): PoolWorker {\n const { workers } = this;\n const at = (k: number) => workers[(index + k) % workers.length] ?? workers[0];\n const k = workers.findIndex((_, k) => !this.dead.has(at(k)));\n\n return at(Math.max(0, k));\n }\n\n /** Sends a message to every worker (a renderer, or its removal, or where the tessellation module is) */\n broadcast(message: Extract<BasemapRequest, { type: 'init' } | { type: 'drop' } | { type: 'tess' }>): void {\n if (this.terminated) return;\n\n // A renderer tells the workers how many they are: they share the decoded tiles' budget\n const sent = message.type === 'init' ? { ...message, workers: this.workers.length } : message;\n\n // A sprite image is copied to each worker (structured clone)\n this.workers.forEach((w) => {\n w.postMessage(sent);\n });\n }\n\n /** Asks a worker for a tile's image or labels, on behalf of `owner` */\n request(worker: PoolWorker, work: BasemapWork, owner: object, signal?: AbortSignal): Promise<BasemapResponse> {\n return new Promise<BasemapResponse>((resolve, reject) => {\n if (this.terminated) return reject(new DOMException('isard: vector tiles destroyed', 'AbortError'));\n if (signal?.aborted) return reject(new DOMException('isard: aborted', 'AbortError'));\n\n const dead = this.dead.get(worker);\n\n if (dead) return reject(dead);\n\n const id = this.next++;\n const abort = () => {\n if (!this.pending.delete(id)) return;\n worker.postMessage({ type: 'abort', id } satisfies BasemapRequest);\n reject(new DOMException('isard: aborted', 'AbortError'));\n };\n // The listener goes once the request is settled\n const settle = () => signal?.removeEventListener('abort', abort);\n\n this.pending.set(id, {\n resolve: (r) => {\n settle();\n resolve(r);\n },\n reject: (e) => {\n settle();\n reject(e);\n },\n worker,\n owner,\n });\n signal?.addEventListener('abort', abort, { once: true });\n worker.postMessage({ ...work, id } satisfies BasemapRequest);\n });\n }\n\n /** The altitudes of a PNG relief tile `z`/`x`/`y` at `url`, decoded by a worker (see `fetchHeights`) */\n heights(\n url: string,\n encoding: PngEncoding,\n floor: number | undefined,\n [z, x, y]: [number, number, number],\n signal: AbortSignal,\n owner: object,\n ): Promise<Float32Array | null> {\n const work: BasemapWork = { type: 'heights', url, encoding, ...(floor === undefined ? {} : { floor }) };\n\n return this.request(this.worker(z, x, y), work, owner, signal).then((r) => ('heights' in r ? r.heights : null));\n }\n\n /** Mercator tile `z`/`x`/`y` reprojected by a worker from the source images of its plan (see `resampler`) */\n reproject(\n job: Job,\n [z, x, y]: [number, number, number],\n signal: AbortSignal,\n owner: object,\n ): Promise<ImageBitmap | null> {\n // Blocks of 4 × 4 Mercator tiles go to the same worker: neighbours share source tiles, each worker keeps its share\n const worker = this.worker(Math.max(0, z - 2), x >> 2, y >> 2);\n const cached = Math.max(16, Math.ceil(SOURCE_CACHE / this.workers.length));\n const work: BasemapWork = { type: 'reproject', job, cached };\n\n return this.request(worker, work, owner, signal).then((r) => ('image' in r ? r.image : null));\n }\n\n /** A GRIB2 or NetCDF file (its URL, fetched by the worker, or its bytes, transferred) read into grids by the grid\n * module (`module`), in the next worker */\n grids(\n source: { url: string } | { bytes: ArrayBuffer },\n module: string,\n signal: AbortSignal | undefined,\n owner: object,\n ): Promise<{ grids: GridDescription[]; values: Float32Array[] }> {\n const work: BasemapWork = { type: 'grids', module, ...source };\n\n this.turn = (this.turn + 1) % this.workers.length;\n\n return this.request(this.living(this.turn), work, owner, signal).then((r) =>\n 'grids' in r ? { grids: r.grids, values: r.values } : { grids: [], values: [] },\n );\n }\n\n /** Cancels the requests of an owner (the workers stop them) */\n cancel(owner: object): void {\n this.pending.forEach((p, id) => {\n if (p.owner !== owner) return;\n this.pending.delete(id);\n p.worker.postMessage({ type: 'abort', id } satisfies BasemapRequest);\n p.reject(new DOMException('isard: vector tiles destroyed', 'AbortError'));\n });\n }\n\n /** Stops the workers; their requests fail */\n terminate(): void {\n if (this.terminated) return;\n this.terminated = true;\n this.unfollow();\n this.workers.forEach((w) => {\n w.terminate();\n });\n\n const pending = [...this.pending.values()];\n\n this.pending.clear();\n pending.forEach((p) => {\n p.reject(new DOMException('isard: vector tiles destroyed', 'AbortError'));\n });\n }\n}\n"]}
@@ -44,7 +44,7 @@ const OWN_SETTERS = {
44
44
  symbols: new Set(['data', 'filter']),
45
45
  extrusions: new Set(['data', 'filter', 'values']),
46
46
  network: new Set(['costs', 'edgeWidths', 'values']),
47
- tiles3d: new Set(['facades']),
47
+ tiles3d: new Set(['facades', 'drape']),
48
48
  models: new Set(['instances', 'altitudeReference']),
49
49
  ground: new Set(['uniforms', 'textures']),
50
50
  flow: new Set(['field', 'fields', 'time', 'playing']),
@@ -122,6 +122,8 @@ export const applyLayerChange = (layer, next, change) => {
122
122
  }
123
123
  if ('facades' in own)
124
124
  set(layer, 'setFacades', own.facades ?? false);
125
+ if ('drape' in own)
126
+ set(layer, 'setDrape', own.drape);
125
127
  if (Object.keys(change.style).length > 0)
126
128
  set(layer, 'setStyle', change.style);
127
129
  };
@@ -1 +1 @@
1
- {"version":3,"file":"layers.js","sourceRoot":"","sources":["../../src/bind/layers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a framework's binding (isard/react, isard/vue) does when the description of a layer changes: the least the\n * layer needs (its data, its style, its instances), or a new layer in its place when what changed is set at creation\n * (its URL, its grid, its nodes). Free of any framework.\n */\n\nimport type { Layer } from '../layers/layers.ts';\nimport type { GeoMap, LayerSpec } from '../map.ts';\n\n/** A layer as a binding describes it: the options of `map.add`, and the values of its features or nodes\n * (`setValues`: what colors them by a ramp) */\nexport type BoundLayerSpec<P = Record<string, unknown>> = LayerSpec<P> & { values?: Float32Array };\n\n/** The keys `setStyle` takes, by layer type; `'all'`: every key but the data (the feature layers) */\nconst STYLE_KEYS: Record<LayerSpec['type'], 'all' | ReadonlySet<string>> = {\n lines: 'all',\n circles: 'all',\n fills: 'all',\n symbols: 'all',\n extrusions: 'all',\n raster: new Set(['opacity', 'saturation']),\n network: new Set(['width', 'max', 'contour', 'opacity', 'halo', 'haloOpacity', 'ramp', 'unreachedColor', 'fade']),\n tiles3d: new Set(['maxScreenSpaceError', 'opacity', 'pointSize', 'color', 'featureColor']),\n pointcloud: new Set([\n 'colorBy',\n 'pointSize',\n 'maxPointSize',\n 'sizeMode',\n 'shape',\n 'edl',\n 'classifications',\n 'elevationRange',\n 'elevationRamp',\n 'intensityRange',\n 'maxScreenSpaceError',\n 'pointBudget',\n ]),\n models: new Set(),\n trees: new Set(),\n ground: new Set(),\n flow: new Set(['colors', 'width', 'opacity', 'height', 'speed', 'density']),\n};\n\n/** Keys a layer takes at its creation only, by layer type: a change makes it anew (whatever its style keys say) */\nconst CREATION_KEYS: Partial<Record<LayerSpec['type'], ReadonlySet<string>>> = {\n lines: new Set(['altitudeReference']),\n};\n\n/** Keys a layer takes by a method of its own, by layer type */\nconst OWN_SETTERS: Partial<Record<LayerSpec['type'], ReadonlySet<string>>> = {\n lines: new Set(['data', 'filter', 'values']),\n circles: new Set(['data', 'filter', 'values']),\n fills: new Set(['data', 'filter', 'values']),\n symbols: new Set(['data', 'filter']),\n extrusions: new Set(['data', 'filter', 'values']),\n network: new Set(['costs', 'edgeWidths', 'values']),\n tiles3d: new Set(['facades']),\n models: new Set(['instances', 'altitudeReference']),\n ground: new Set(['uniforms', 'textures']),\n flow: new Set(['field', 'fields', 'time', 'playing']),\n};\n\n/** The keys of a description and their values */\nconst fields = (spec: BoundLayerSpec): Map<string, unknown> => new Map(Object.entries(spec));\n\n/** What to do with a layer whose description went from `prev` to `next` */\nexport type LayerChange =\n | { rebuild: true }\n | {\n rebuild: false;\n /** The keys changed, with their new values */\n style: Record<string, unknown>;\n own: Record<string, unknown>;\n };\n\n/**\n * The change from one description to the next, or `undefined` when nothing changed. Values are compared by identity:\n * data, functions and arrays given anew at each render are changes (keep them in a memo)\n */\nexport const layerChange = (prev: BoundLayerSpec, next: BoundLayerSpec): LayerChange | undefined => {\n if (prev.type !== next.type) return { rebuild: true };\n\n const before = fields(prev);\n const after = fields(next);\n const styleKeys = STYLE_KEYS[next.type];\n const own = OWN_SETTERS[next.type];\n const change: Extract<LayerChange, { rebuild: false }> = { rebuild: false, style: {}, own: {} };\n const keys = [...new Set([...before.keys(), ...after.keys()])].filter(\n (key) => key !== 'type' && !Object.is(before.get(key), after.get(key)),\n );\n\n if (keys.length === 0) return undefined;\n\n const creation = CREATION_KEYS[next.type];\n const isStyle = (key: string) =>\n key !== 'before' && !creation?.has(key) && (styleKeys === 'all' || styleKeys.has(key));\n\n // A style or setting taken away: the layer goes back to its defaults, as made anew\n if (keys.some((key) => !after.has(key) || !(own?.has(key) || isStyle(key)))) return { rebuild: true };\n keys.forEach((key) => {\n if (own?.has(key)) change.own[key] = after.get(key);\n else change.style[key] = after.get(key);\n });\n\n return change;\n};\n\n/** The methods a change calls on a layer, those of its type */\ntype Setter =\n | 'setStyle'\n | 'setFacades'\n | 'setData'\n | 'setFilter'\n | 'setValues'\n | 'setCosts'\n | 'setEdgeWidths'\n | 'setInstances'\n | 'setUniform'\n | 'setTexture'\n | 'setField'\n | 'setFields'\n | 'setTime'\n | 'setPlaying';\n\n/** Calls a setter of the layer, if its type has it */\nconst set = (layer: Layer, setter: Setter, ...args: unknown[]): void => {\n const method: unknown = Reflect.get(layer, setter);\n\n if (typeof method === 'function') method.apply(layer, args);\n};\n\n/** Applies a change that keeps the layer (`rebuild: false`) */\nexport const applyLayerChange = (\n layer: Layer,\n next: BoundLayerSpec,\n change: Extract<LayerChange, { rebuild: false }>,\n): void => {\n const spec = fields(next);\n const own = change.own;\n\n if ('data' in own) set(layer, 'setData', own.data);\n if ('filter' in own) set(layer, 'setFilter', own.filter);\n if ('values' in own) set(layer, 'setValues', own.values);\n if ('field' in own) set(layer, 'setField', own.field);\n if ('fields' in own) set(layer, 'setFields', own.fields, spec.get('time'));\n else if ('time' in own) set(layer, 'setTime', own.time);\n if ('playing' in own) set(layer, 'setPlaying', own.playing ?? true);\n if ('costs' in own) set(layer, 'setCosts', own.costs);\n if ('edgeWidths' in own) set(layer, 'setEdgeWidths', own.edgeWidths);\n if ('instances' in own || 'altitudeReference' in own) {\n set(layer, 'setInstances', spec.get('instances'), spec.get('altitudeReference'));\n }\n if ('uniforms' in own) {\n Object.entries(own.uniforms ?? {}).forEach(([name, value]) => {\n set(layer, 'setUniform', name, value);\n });\n }\n if ('textures' in own) {\n Object.entries(own.textures ?? {}).forEach(([name, texture]) => {\n set(layer, 'setTexture', name, texture);\n });\n }\n if ('facades' in own) set(layer, 'setFacades', own.facades ?? false);\n if (Object.keys(change.style).length > 0) set(layer, 'setStyle', change.style);\n};\n\n/** Adds a layer from its description, its values set */\nexport const addBoundLayer = (map: GeoMap, { values, ...spec }: BoundLayerSpec): Layer => {\n const layer = map.add(spec as LayerSpec);\n\n if (values) set(layer, 'setValues', values);\n\n return layer;\n};\n\n/** A layer made anew from its description in the place of `old`, its values set */\nexport const rebuildBoundLayer = (map: GeoMap, old: Layer, { values, ...spec }: BoundLayerSpec): Layer => {\n const layer = map.rebuildLayer(old, spec as LayerSpec);\n\n if (values) set(layer, 'setValues', values);\n\n return layer;\n};\n\n/**\n * The layers of a binding in their declared order: `order` (default 0) from the bottom up, layers of the same order by\n * their `rank` (where they were declared: a component's taken when it first renders, before its layer may wait for\n * something, its tiles or its data), else by the time they came. A layer added or made anew is moved under the first\n * layer above it\n */\nexport class LayerOrder {\n private readonly entries: { layer: Layer; order: number; seq: number }[] = [];\n private seq = 0;\n\n /** The next rank: a component's place among the others, taken as React renders them in their declared order */\n rank(): number {\n this.seq += 1;\n\n return this.seq;\n }\n\n /** Places a new layer (at its `rank`, else after every other), or a layer made anew in place of `old` */\n place(layer: Layer, order: number, { old, rank }: { old?: Layer | undefined; rank?: number | undefined } = {}): void {\n const index = old ? this.entries.findIndex((e) => e.layer === old) : -1;\n const entry = index >= 0 ? this.entries[index] : undefined;\n\n if (entry) {\n entry.layer = layer;\n entry.order = order;\n } else {\n this.entries.push({ layer, order, seq: rank ?? this.rank() });\n }\n this.entries.sort((a, b) => a.order - b.order || a.seq - b.seq);\n\n const at = this.entries.findIndex((e) => e.layer === layer);\n const above = this.entries[at + 1]?.layer;\n\n if (above) layer.moveBefore(above);\n }\n\n /** Forgets a layer removed */\n remove(layer: Layer): void {\n const index = this.entries.findIndex((e) => e.layer === layer);\n\n if (index >= 0) this.entries.splice(index, 1);\n }\n}\n"]}
1
+ {"version":3,"file":"layers.js","sourceRoot":"","sources":["../../src/bind/layers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a framework's binding (isard/react, isard/vue) does when the description of a layer changes: the least the\n * layer needs (its data, its style, its instances), or a new layer in its place when what changed is set at creation\n * (its URL, its grid, its nodes). Free of any framework.\n */\n\nimport type { Layer } from '../layers/layers.ts';\nimport type { GeoMap, LayerSpec } from '../map.ts';\n\n/** A layer as a binding describes it: the options of `map.add`, and the values of its features or nodes\n * (`setValues`: what colors them by a ramp) */\nexport type BoundLayerSpec<P = Record<string, unknown>> = LayerSpec<P> & { values?: Float32Array };\n\n/** The keys `setStyle` takes, by layer type; `'all'`: every key but the data (the feature layers) */\nconst STYLE_KEYS: Record<LayerSpec['type'], 'all' | ReadonlySet<string>> = {\n lines: 'all',\n circles: 'all',\n fills: 'all',\n symbols: 'all',\n extrusions: 'all',\n raster: new Set(['opacity', 'saturation']),\n network: new Set(['width', 'max', 'contour', 'opacity', 'halo', 'haloOpacity', 'ramp', 'unreachedColor', 'fade']),\n tiles3d: new Set(['maxScreenSpaceError', 'opacity', 'pointSize', 'color', 'featureColor']),\n pointcloud: new Set([\n 'colorBy',\n 'pointSize',\n 'maxPointSize',\n 'sizeMode',\n 'shape',\n 'edl',\n 'classifications',\n 'elevationRange',\n 'elevationRamp',\n 'intensityRange',\n 'maxScreenSpaceError',\n 'pointBudget',\n ]),\n models: new Set(),\n trees: new Set(),\n ground: new Set(),\n flow: new Set(['colors', 'width', 'opacity', 'height', 'speed', 'density']),\n};\n\n/** Keys a layer takes at its creation only, by layer type: a change makes it anew (whatever its style keys say) */\nconst CREATION_KEYS: Partial<Record<LayerSpec['type'], ReadonlySet<string>>> = {\n lines: new Set(['altitudeReference']),\n};\n\n/** Keys a layer takes by a method of its own, by layer type */\nconst OWN_SETTERS: Partial<Record<LayerSpec['type'], ReadonlySet<string>>> = {\n lines: new Set(['data', 'filter', 'values']),\n circles: new Set(['data', 'filter', 'values']),\n fills: new Set(['data', 'filter', 'values']),\n symbols: new Set(['data', 'filter']),\n extrusions: new Set(['data', 'filter', 'values']),\n network: new Set(['costs', 'edgeWidths', 'values']),\n tiles3d: new Set(['facades', 'drape']),\n models: new Set(['instances', 'altitudeReference']),\n ground: new Set(['uniforms', 'textures']),\n flow: new Set(['field', 'fields', 'time', 'playing']),\n};\n\n/** The keys of a description and their values */\nconst fields = (spec: BoundLayerSpec): Map<string, unknown> => new Map(Object.entries(spec));\n\n/** What to do with a layer whose description went from `prev` to `next` */\nexport type LayerChange =\n | { rebuild: true }\n | {\n rebuild: false;\n /** The keys changed, with their new values */\n style: Record<string, unknown>;\n own: Record<string, unknown>;\n };\n\n/**\n * The change from one description to the next, or `undefined` when nothing changed. Values are compared by identity:\n * data, functions and arrays given anew at each render are changes (keep them in a memo)\n */\nexport const layerChange = (prev: BoundLayerSpec, next: BoundLayerSpec): LayerChange | undefined => {\n if (prev.type !== next.type) return { rebuild: true };\n\n const before = fields(prev);\n const after = fields(next);\n const styleKeys = STYLE_KEYS[next.type];\n const own = OWN_SETTERS[next.type];\n const change: Extract<LayerChange, { rebuild: false }> = { rebuild: false, style: {}, own: {} };\n const keys = [...new Set([...before.keys(), ...after.keys()])].filter(\n (key) => key !== 'type' && !Object.is(before.get(key), after.get(key)),\n );\n\n if (keys.length === 0) return undefined;\n\n const creation = CREATION_KEYS[next.type];\n const isStyle = (key: string) =>\n key !== 'before' && !creation?.has(key) && (styleKeys === 'all' || styleKeys.has(key));\n\n // A style or setting taken away: the layer goes back to its defaults, as made anew\n if (keys.some((key) => !after.has(key) || !(own?.has(key) || isStyle(key)))) return { rebuild: true };\n keys.forEach((key) => {\n if (own?.has(key)) change.own[key] = after.get(key);\n else change.style[key] = after.get(key);\n });\n\n return change;\n};\n\n/** The methods a change calls on a layer, those of its type */\ntype Setter =\n | 'setStyle'\n | 'setFacades'\n | 'setDrape'\n | 'setData'\n | 'setFilter'\n | 'setValues'\n | 'setCosts'\n | 'setEdgeWidths'\n | 'setInstances'\n | 'setUniform'\n | 'setTexture'\n | 'setField'\n | 'setFields'\n | 'setTime'\n | 'setPlaying';\n\n/** Calls a setter of the layer, if its type has it */\nconst set = (layer: Layer, setter: Setter, ...args: unknown[]): void => {\n const method: unknown = Reflect.get(layer, setter);\n\n if (typeof method === 'function') method.apply(layer, args);\n};\n\n/** Applies a change that keeps the layer (`rebuild: false`) */\nexport const applyLayerChange = (\n layer: Layer,\n next: BoundLayerSpec,\n change: Extract<LayerChange, { rebuild: false }>,\n): void => {\n const spec = fields(next);\n const own = change.own;\n\n if ('data' in own) set(layer, 'setData', own.data);\n if ('filter' in own) set(layer, 'setFilter', own.filter);\n if ('values' in own) set(layer, 'setValues', own.values);\n if ('field' in own) set(layer, 'setField', own.field);\n if ('fields' in own) set(layer, 'setFields', own.fields, spec.get('time'));\n else if ('time' in own) set(layer, 'setTime', own.time);\n if ('playing' in own) set(layer, 'setPlaying', own.playing ?? true);\n if ('costs' in own) set(layer, 'setCosts', own.costs);\n if ('edgeWidths' in own) set(layer, 'setEdgeWidths', own.edgeWidths);\n if ('instances' in own || 'altitudeReference' in own) {\n set(layer, 'setInstances', spec.get('instances'), spec.get('altitudeReference'));\n }\n if ('uniforms' in own) {\n Object.entries(own.uniforms ?? {}).forEach(([name, value]) => {\n set(layer, 'setUniform', name, value);\n });\n }\n if ('textures' in own) {\n Object.entries(own.textures ?? {}).forEach(([name, texture]) => {\n set(layer, 'setTexture', name, texture);\n });\n }\n if ('facades' in own) set(layer, 'setFacades', own.facades ?? false);\n if ('drape' in own) set(layer, 'setDrape', own.drape);\n if (Object.keys(change.style).length > 0) set(layer, 'setStyle', change.style);\n};\n\n/** Adds a layer from its description, its values set */\nexport const addBoundLayer = (map: GeoMap, { values, ...spec }: BoundLayerSpec): Layer => {\n const layer = map.add(spec as LayerSpec);\n\n if (values) set(layer, 'setValues', values);\n\n return layer;\n};\n\n/** A layer made anew from its description in the place of `old`, its values set */\nexport const rebuildBoundLayer = (map: GeoMap, old: Layer, { values, ...spec }: BoundLayerSpec): Layer => {\n const layer = map.rebuildLayer(old, spec as LayerSpec);\n\n if (values) set(layer, 'setValues', values);\n\n return layer;\n};\n\n/**\n * The layers of a binding in their declared order: `order` (default 0) from the bottom up, layers of the same order by\n * their `rank` (where they were declared: a component's taken when it first renders, before its layer may wait for\n * something, its tiles or its data), else by the time they came. A layer added or made anew is moved under the first\n * layer above it\n */\nexport class LayerOrder {\n private readonly entries: { layer: Layer; order: number; seq: number }[] = [];\n private seq = 0;\n\n /** The next rank: a component's place among the others, taken as React renders them in their declared order */\n rank(): number {\n this.seq += 1;\n\n return this.seq;\n }\n\n /** Places a new layer (at its `rank`, else after every other), or a layer made anew in place of `old` */\n place(layer: Layer, order: number, { old, rank }: { old?: Layer | undefined; rank?: number | undefined } = {}): void {\n const index = old ? this.entries.findIndex((e) => e.layer === old) : -1;\n const entry = index >= 0 ? this.entries[index] : undefined;\n\n if (entry) {\n entry.layer = layer;\n entry.order = order;\n } else {\n this.entries.push({ layer, order, seq: rank ?? this.rank() });\n }\n this.entries.sort((a, b) => a.order - b.order || a.seq - b.seq);\n\n const at = this.entries.findIndex((e) => e.layer === layer);\n const above = this.entries[at + 1]?.layer;\n\n if (above) layer.moveBefore(above);\n }\n\n /** Forgets a layer removed */\n remove(layer: Layer): void {\n const index = this.entries.findIndex((e) => e.layer === layer);\n\n if (index >= 0) this.entries.splice(index, 1);\n }\n}\n"]}