isard 1.3.0 → 1.5.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 (97) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +23 -6
  3. package/dist/basemap/basemaps.js +1 -0
  4. package/dist/basemap/basemaps.js.map +1 -1
  5. package/dist/basemap/vectortiles/context.d.ts +43 -0
  6. package/dist/basemap/vectortiles/context.js +6 -0
  7. package/dist/basemap/vectortiles/context.js.map +1 -0
  8. package/dist/basemap/vectortiles/extrusions.d.ts +11 -0
  9. package/dist/basemap/vectortiles/extrusions.js +46 -0
  10. package/dist/basemap/vectortiles/extrusions.js.map +1 -0
  11. package/dist/basemap/vectortiles/labels.d.ts +22 -0
  12. package/dist/basemap/vectortiles/labels.js +225 -0
  13. package/dist/basemap/vectortiles/labels.js.map +1 -0
  14. package/dist/basemap/vectortiles/requests.d.ts +24 -0
  15. package/dist/basemap/vectortiles/requests.js +61 -0
  16. package/dist/basemap/vectortiles/requests.js.map +1 -0
  17. package/dist/basemap/vectortiles/street-wind.d.ts +19 -0
  18. package/dist/basemap/vectortiles/street-wind.js +133 -0
  19. package/dist/basemap/vectortiles/street-wind.js.map +1 -0
  20. package/dist/basemap/vectortiles/style.d.ts +47 -0
  21. package/dist/basemap/vectortiles/style.js +141 -0
  22. package/dist/basemap/vectortiles/style.js.map +1 -0
  23. package/dist/basemap/vectortiles/tiles.d.ts +34 -0
  24. package/dist/basemap/vectortiles/tiles.js +62 -0
  25. package/dist/basemap/vectortiles/tiles.js.map +1 -0
  26. package/dist/basemap/vectortiles/trees.d.ts +19 -0
  27. package/dist/basemap/vectortiles/trees.js +93 -0
  28. package/dist/basemap/vectortiles/trees.js.map +1 -0
  29. package/dist/basemap/vectortiles/vectors.d.ts +20 -0
  30. package/dist/basemap/vectortiles/vectors.js +167 -0
  31. package/dist/basemap/vectortiles/vectors.js.map +1 -0
  32. package/dist/basemap/vectortiles.d.ts +34 -75
  33. package/dist/basemap/vectortiles.js +70 -654
  34. package/dist/basemap/vectortiles.js.map +1 -1
  35. package/dist/basemap/workerpool.js +33 -5
  36. package/dist/basemap/workerpool.js.map +1 -1
  37. package/dist/basemap.worker.js +2 -2
  38. package/dist/basemap.worker.js.map +8 -5
  39. package/dist/bind/layers.js +10 -0
  40. package/dist/bind/layers.js.map +1 -1
  41. package/dist/decoder.worker.js +5 -4
  42. package/dist/decoder.worker.js.map +8 -6
  43. package/dist/engine/decoders.d.ts +4 -8
  44. package/dist/engine/decoders.js +29 -2
  45. package/dist/engine/decoders.js.map +1 -1
  46. package/dist/engine-loader.d.ts +4 -1
  47. package/dist/engine-loader.js +9 -0
  48. package/dist/engine-loader.js.map +1 -1
  49. package/dist/grid-module.d.ts +44 -0
  50. package/dist/grid-module.js +63 -0
  51. package/dist/grid-module.js.map +1 -0
  52. package/dist/grids.d.ts +51 -0
  53. package/dist/grids.js +88 -0
  54. package/dist/grids.js.map +1 -0
  55. package/dist/index.d.ts +10 -1
  56. package/dist/index.js +3 -1
  57. package/dist/index.js.map +1 -1
  58. package/dist/isard_bg.wasm +0 -0
  59. package/dist/isard_core_bg.wasm +0 -0
  60. package/dist/isard_grid_bg.wasm +0 -0
  61. package/dist/layers/flow.d.ts +118 -0
  62. package/dist/layers/flow.js +263 -0
  63. package/dist/layers/flow.js.map +1 -0
  64. package/dist/layers/panoramas.d.ts +2 -0
  65. package/dist/layers/panoramas.js +27 -6
  66. package/dist/layers/panoramas.js.map +1 -1
  67. package/dist/layers/symbols.d.ts +2 -0
  68. package/dist/layers/symbols.js +2 -1
  69. package/dist/layers/symbols.js.map +1 -1
  70. package/dist/map/layer-spec.d.ts +4 -1
  71. package/dist/map/layer-spec.js +2 -0
  72. package/dist/map/layer-spec.js.map +1 -1
  73. package/dist/map/workers.d.ts +4 -0
  74. package/dist/map/workers.js +38 -0
  75. package/dist/map/workers.js.map +1 -1
  76. package/dist/map.d.ts +14 -0
  77. package/dist/map.js +19 -1
  78. package/dist/map.js.map +1 -1
  79. package/dist/react/Layer.d.ts +2 -0
  80. package/dist/react/Layer.js.map +1 -1
  81. package/dist/types.d.ts +7 -3
  82. package/dist/types.js.map +1 -1
  83. package/dist/util/read.d.ts +4 -0
  84. package/dist/util/read.js +28 -0
  85. package/dist/util/read.js.map +1 -0
  86. package/dist/wasm/isard.d.ts +55 -0
  87. package/dist/wasm/isard.js +112 -1
  88. package/dist/wasm/isard_core.d.ts +55 -0
  89. package/dist/wasm/isard_core.js +112 -1
  90. package/dist/wasm/isard_grid.d.ts +101 -0
  91. package/dist/wasm/isard_grid.js +375 -0
  92. package/dist/workers/basemap/street.d.ts +19 -0
  93. package/dist/workers/basemap.worker.d.ts +21 -0
  94. package/dist/workers/basemap.worker.js +23 -4
  95. package/dist/workers/basemap.worker.js.map +1 -1
  96. package/package.json +2 -1
  97. package/vite.js +3 -2
@@ -1,15 +1,11 @@
1
- /**
2
- * Optional decoders of the worker, loaded on first use from configurable URLs (the official builds three.js and
3
- * Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),
4
- * transcoded to the best compressed format the GPU supports.
5
- */
6
1
  import type { CompressedTexture, DracoGeometry, DracoRequest, TextureFormats } from '../wasm/isard.js';
7
2
  /**
8
3
  * Base URLs of the decoders (each ending with `/`).
9
4
  *
10
- * The decoders are Emscripten builds published as classic scripts: the worker fetches the script and runs it with
11
- * `new Function`, so a Content Security Policy must allow `'unsafe-eval'` in `script-src` (or `worker-src`) for 3D
12
- * Tiles that use Draco or KTX2. They are fetched from the default CDNs; to self-host them (offline, locked-down
5
+ * The decoders are Emscripten builds published as classic scripts: the worker fetches the script and imports it as a
6
+ * module from a `blob:` URL, so a Content Security Policy needs `blob:` in `script-src` (or `worker-src`) for 3D Tiles
7
+ * that use Draco; it falls back on `new Function` (`'unsafe-eval'`) where `blob:` is refused. The Basis transcoder (KTX2)
8
+ * needs `'unsafe-eval'` anyway: its own bindings (embind) build functions from strings. They are fetched from the default CDNs; to self-host them (offline, locked-down
13
9
  * networks, no third-party requests), copy the four files (`draco_wasm_wrapper_gltf.js`, `draco_decoder_gltf.wasm`
14
10
  * from the Draco release, `basis_transcoder.js`, `basis_transcoder.wasm` from three.js's `examples/jsm/libs/basis/`)
15
11
  * to your server and give their folders in `GeoMapOptions.decoders`.
@@ -1,11 +1,38 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ /**
10
+ * Optional decoders of the worker, loaded on first use from configurable URLs (the official builds three.js and
11
+ * Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),
12
+ * transcoded to the best compressed format the GPU supports.
13
+ */
14
+ import { isRecord } from "../util/guards.js";
1
15
  export const DEFAULT_DECODERS = {
2
16
  draco: 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/',
3
17
  basis: 'https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/libs/basis/',
4
18
  };
5
- /** Loads an Emscripten factory published as a classic script (module workers have no importScripts); needs
6
- * `'unsafe-eval'` under a Content Security Policy (see `DecoderUrls`) */
19
+ /** Loads an Emscripten factory published as a classic script (module workers have no importScripts): imported as a
20
+ * module from a `blob:` URL (a Content Security Policy allowing `blob:` scripts is enough), else evaluated (where
21
+ * `blob:` is refused: `'unsafe-eval'`, see `DecoderUrls`) */
7
22
  const factory = async (url, name) => {
8
23
  const source = await (await fetch(url)).text();
24
+ const blob = URL.createObjectURL(new Blob([`${source}\nexport default ${name};`], { type: 'text/javascript' }));
25
+ try {
26
+ const module = await import(__rewriteRelativeImportExtension(/* @vite-ignore */ blob));
27
+ if (isRecord(module) && typeof module.default === 'function')
28
+ return module.default;
29
+ }
30
+ catch {
31
+ // Refused (`blob:` not allowed): evaluated below
32
+ }
33
+ finally {
34
+ URL.revokeObjectURL(blob);
35
+ }
9
36
  return new Function(`${source}\nreturn ${name};`)();
10
37
  };
11
38
  const instantiate = async (base, script, wasm, name) => {
@@ -1 +1 @@
1
- {"version":3,"file":"decoders.js","sourceRoot":"","sources":["../../src/engine/decoders.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Optional decoders of the worker, loaded on first use from configurable URLs (the official builds three.js and\n * Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),\n * transcoded to the best compressed format the GPU supports.\n */\nimport type { CompressedTexture, DracoGeometry, DracoRequest, TextureFormats } from '../wasm/isard.js';\n\n/**\n * Base URLs of the decoders (each ending with `/`).\n *\n * The decoders are Emscripten builds published as classic scripts: the worker fetches the script and runs it with\n * `new Function`, so a Content Security Policy must allow `'unsafe-eval'` in `script-src` (or `worker-src`) for 3D\n * Tiles that use Draco or KTX2. They are fetched from the default CDNs; to self-host them (offline, locked-down\n * networks, no third-party requests), copy the four files (`draco_wasm_wrapper_gltf.js`, `draco_decoder_gltf.wasm`\n * from the Draco release, `basis_transcoder.js`, `basis_transcoder.wasm` from three.js's `examples/jsm/libs/basis/`)\n * to your server and give their folders in `GeoMapOptions.decoders`.\n */\nexport interface DecoderUrls {\n /** Folder of `draco_wasm_wrapper_gltf.js` and `draco_decoder_gltf.wasm` (and, for Draco point clouds, of the full\n * decoder `draco_wasm_wrapper.js` and `draco_decoder.wasm`) */\n draco: string;\n /** Folder of `basis_transcoder.js` and `basis_transcoder.wasm` */\n basis: string;\n}\n\nexport const DEFAULT_DECODERS: DecoderUrls = {\n draco: 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/',\n basis: 'https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/libs/basis/',\n};\n\n// ── Draco (the subset of its Emscripten API used here) ──\n\ninterface DracoStatus {\n ok(): boolean;\n error_msg(): string;\n}\ninterface DracoMesh {\n num_points(): number;\n num_faces(): number;\n}\ninterface DracoAttribute {\n num_components(): number;\n}\ninterface DracoDecoder {\n DecodeArrayToMesh(data: Int8Array, size: number, mesh: DracoMesh): DracoStatus;\n DecodeArrayToPointCloud(data: Int8Array, size: number, cloud: DracoMesh): DracoStatus;\n GetAttributeByUniqueId(mesh: DracoMesh, id: number): DracoAttribute;\n GetAttributeDataArrayForAllPoints(\n mesh: DracoMesh,\n attribute: DracoAttribute,\n type: number,\n bytes: number,\n pointer: number,\n ): boolean;\n GetTrianglesUInt32Array(mesh: DracoMesh, bytes: number, pointer: number): boolean;\n}\ninterface DracoModule {\n Decoder: new () => DracoDecoder;\n Mesh: new () => DracoMesh;\n PointCloud: new () => DracoMesh;\n DT_FLOAT32: number;\n HEAPF32: Float32Array;\n HEAPU32: Uint32Array;\n _malloc(bytes: number): number;\n _free(pointer: number): void;\n destroy(object: object): void;\n}\n\n// ── Basis Universal transcoder ──\n\ninterface KTX2File {\n isValid(): boolean;\n getLevels(): number;\n getHasAlpha(): boolean;\n startTranscoding(): boolean;\n getImageLevelInfo(level: number, layer: number, face: number): { origWidth: number; origHeight: number };\n getImageTranscodedSizeInBytes(level: number, layer: number, face: number, format: number): number;\n transcodeImage(\n target: Uint8Array,\n level: number,\n layer: number,\n face: number,\n format: number,\n alphaForOpaque: number,\n channel0: number,\n channel1: number,\n ): boolean;\n close(): void;\n delete(): void;\n}\ninterface BasisModule {\n initializeBasis(): void;\n KTX2File: new (data: Uint8Array) => KTX2File;\n}\n\ntype Factory<T> = (options: { wasmBinary: ArrayBuffer }) => Promise<T>;\n\n/** Loads an Emscripten factory published as a classic script (module workers have no importScripts); needs\n * `'unsafe-eval'` under a Content Security Policy (see `DecoderUrls`) */\nconst factory = async <T>(url: string, name: string): Promise<Factory<T>> => {\n const source = await (await fetch(url)).text();\n\n return new Function(`${source}\\nreturn ${name};`)() as Factory<T>;\n};\n\nconst instantiate = async <T>(base: string, script: string, wasm: string, name: string): Promise<T> => {\n const [create, binary] = await Promise.all([\n factory<T>(`${base}${script}`, name),\n fetch(`${base}${wasm}`).then((r) => r.arrayBuffer()),\n ]);\n\n return create({ wasmBinary: binary });\n};\n\nlet draco: Promise<DracoModule> | undefined;\n/** The full Draco decoder: the glTF build decodes meshes only, not the point clouds */\nlet dracoPoints: Promise<DracoModule> | undefined;\nlet basis: Promise<BasisModule> | undefined;\n\n/** Decodes the Draco primitives of a tile (their points alone for point clouds) */\nexport const decodeDraco = async (urls: DecoderUrls, requests: DracoRequest[]): Promise<DracoGeometry[]> => {\n const meshes = requests.some((r) => !r.points);\n\n if (meshes) {\n draco ??= instantiate<DracoModule>(\n urls.draco,\n 'draco_wasm_wrapper_gltf.js',\n 'draco_decoder_gltf.wasm',\n 'DracoDecoderModule',\n );\n }\n if (requests.some((r) => r.points)) {\n dracoPoints ??= instantiate<DracoModule>(\n urls.draco,\n 'draco_wasm_wrapper.js',\n 'draco_decoder.wasm',\n 'DracoDecoderModule',\n );\n }\n\n const [forMeshes, forPoints] = await Promise.all([meshes ? draco : undefined, dracoPoints]);\n\n return requests.map((request) => {\n const module = request.points ? forPoints : forMeshes;\n\n if (!module) throw new Error('isard: the Draco decoder is not loaded');\n\n const decoder = new module.Decoder();\n const mesh = request.points ? new module.PointCloud() : new module.Mesh();\n\n try {\n const data = new Int8Array(request.data.buffer, request.data.byteOffset, request.data.byteLength);\n const status = request.points\n ? decoder.DecodeArrayToPointCloud(data, data.byteLength, mesh)\n : decoder.DecodeArrayToMesh(data, data.byteLength, mesh);\n\n if (!status.ok()) throw new Error(`Draco: ${status.error_msg()}`);\n\n const floats = (id: number): Float32Array => {\n const attribute = decoder.GetAttributeByUniqueId(mesh, id);\n const count = mesh.num_points() * attribute.num_components();\n const pointer = module._malloc(count * 4);\n\n try {\n decoder.GetAttributeDataArrayForAllPoints(mesh, attribute, module.DT_FLOAT32, count * 4, pointer);\n\n return module.HEAPF32.slice(pointer / 4, pointer / 4 + count);\n } finally {\n module._free(pointer);\n }\n };\n\n if (request.points) {\n const geometry: DracoGeometry = {\n mesh: request.mesh,\n primitive: request.primitive,\n positions: floats(request.position),\n };\n\n if (request.color !== undefined) geometry.colors = floats(request.color);\n if (request.normal !== undefined) geometry.normals = floats(request.normal);\n\n return geometry;\n }\n\n const triangles = (): Uint32Array => {\n const count = mesh.num_faces() * 3;\n const pointer = module._malloc(count * 4);\n\n try {\n decoder.GetTrianglesUInt32Array(mesh, count * 4, pointer);\n\n return module.HEAPU32.slice(pointer / 4, pointer / 4 + count);\n } finally {\n module._free(pointer);\n }\n };\n const indices = triangles();\n const geometry: DracoGeometry = {\n mesh: request.mesh,\n primitive: request.primitive,\n positions: floats(request.position),\n indices,\n };\n\n if (request.uv !== undefined) geometry.uvs = floats(request.uv);\n\n return geometry;\n } finally {\n module.destroy(mesh);\n module.destroy(decoder);\n }\n });\n};\n\n/** Basis target format and WebGL internal format, best first */\nconst target = (formats: TextureFormats, alpha: boolean): { basis: number; gl: number } => {\n if (formats.astc) return { basis: 10, gl: 0x93b0 }; // ASTC 4×4\n if (formats.bptc) return { basis: 6, gl: 0x8e8c }; // BC7\n if (formats.etc) return alpha ? { basis: 1, gl: 0x9278 } : { basis: 0, gl: 0x9274 }; // ETC2 RGBA / ETC1 as ETC2 RGB\n if (formats.s3tc) return alpha ? { basis: 3, gl: 0x83f3 } : { basis: 2, gl: 0x83f0 }; // BC3 / BC1\n\n return { basis: 13, gl: 0x8058 }; // RGBA8, uncompressed\n};\n\n/** Transcodes a KTX2 image for the GPU */\nexport const transcodeKtx2 = async (\n urls: DecoderUrls,\n formats: TextureFormats,\n bytes: Uint8Array,\n): Promise<CompressedTexture> => {\n basis ??= instantiate<BasisModule>(urls.basis, 'basis_transcoder.js', 'basis_transcoder.wasm', 'BASIS').then((m) => {\n m.initializeBasis();\n\n return m;\n });\n\n const module = await basis;\n const file = new module.KTX2File(bytes);\n\n try {\n if (!file.isValid() || !file.startTranscoding()) throw new Error('KTX2: invalid file');\n\n const { basis: format, gl } = target(formats, file.getHasAlpha());\n const levels: CompressedTexture['levels'] = Array.from({ length: file.getLevels() }, (_, level) => {\n const { origWidth: width, origHeight: height } = file.getImageLevelInfo(level, 0, 0);\n const data = new Uint8Array(file.getImageTranscodedSizeInBytes(level, 0, 0, format));\n\n if (!file.transcodeImage(data, level, 0, 0, format, 0, -1, -1)) throw new Error('KTX2: transcoding failed');\n\n return { width, height, data };\n });\n\n return { format: gl, levels };\n } finally {\n file.close();\n file.delete();\n }\n};\n"]}
1
+ {"version":3,"file":"decoders.js","sourceRoot":"","sources":["../../src/engine/decoders.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Optional decoders of the worker, loaded on first use from configurable URLs (the official builds three.js and\n * Cesium use): Draco geometry (`KHR_draco_mesh_compression`) and KTX2 / Basis Universal textures (`KHR_texture_basisu`),\n * transcoded to the best compressed format the GPU supports.\n */\nimport { isRecord } from '../util/guards.ts';\nimport type { CompressedTexture, DracoGeometry, DracoRequest, TextureFormats } from '../wasm/isard.js';\n\n/**\n * Base URLs of the decoders (each ending with `/`).\n *\n * The decoders are Emscripten builds published as classic scripts: the worker fetches the script and imports it as a\n * module from a `blob:` URL, so a Content Security Policy needs `blob:` in `script-src` (or `worker-src`) for 3D Tiles\n * that use Draco; it falls back on `new Function` (`'unsafe-eval'`) where `blob:` is refused. The Basis transcoder (KTX2)\n * needs `'unsafe-eval'` anyway: its own bindings (embind) build functions from strings. They are fetched from the default CDNs; to self-host them (offline, locked-down\n * networks, no third-party requests), copy the four files (`draco_wasm_wrapper_gltf.js`, `draco_decoder_gltf.wasm`\n * from the Draco release, `basis_transcoder.js`, `basis_transcoder.wasm` from three.js's `examples/jsm/libs/basis/`)\n * to your server and give their folders in `GeoMapOptions.decoders`.\n */\nexport interface DecoderUrls {\n /** Folder of `draco_wasm_wrapper_gltf.js` and `draco_decoder_gltf.wasm` (and, for Draco point clouds, of the full\n * decoder `draco_wasm_wrapper.js` and `draco_decoder.wasm`) */\n draco: string;\n /** Folder of `basis_transcoder.js` and `basis_transcoder.wasm` */\n basis: string;\n}\n\nexport const DEFAULT_DECODERS: DecoderUrls = {\n draco: 'https://www.gstatic.com/draco/versioned/decoders/1.5.7/',\n basis: 'https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/libs/basis/',\n};\n\n// ── Draco (the subset of its Emscripten API used here) ──\n\ninterface DracoStatus {\n ok(): boolean;\n error_msg(): string;\n}\ninterface DracoMesh {\n num_points(): number;\n num_faces(): number;\n}\ninterface DracoAttribute {\n num_components(): number;\n}\ninterface DracoDecoder {\n DecodeArrayToMesh(data: Int8Array, size: number, mesh: DracoMesh): DracoStatus;\n DecodeArrayToPointCloud(data: Int8Array, size: number, cloud: DracoMesh): DracoStatus;\n GetAttributeByUniqueId(mesh: DracoMesh, id: number): DracoAttribute;\n GetAttributeDataArrayForAllPoints(\n mesh: DracoMesh,\n attribute: DracoAttribute,\n type: number,\n bytes: number,\n pointer: number,\n ): boolean;\n GetTrianglesUInt32Array(mesh: DracoMesh, bytes: number, pointer: number): boolean;\n}\ninterface DracoModule {\n Decoder: new () => DracoDecoder;\n Mesh: new () => DracoMesh;\n PointCloud: new () => DracoMesh;\n DT_FLOAT32: number;\n HEAPF32: Float32Array;\n HEAPU32: Uint32Array;\n _malloc(bytes: number): number;\n _free(pointer: number): void;\n destroy(object: object): void;\n}\n\n// ── Basis Universal transcoder ──\n\ninterface KTX2File {\n isValid(): boolean;\n getLevels(): number;\n getHasAlpha(): boolean;\n startTranscoding(): boolean;\n getImageLevelInfo(level: number, layer: number, face: number): { origWidth: number; origHeight: number };\n getImageTranscodedSizeInBytes(level: number, layer: number, face: number, format: number): number;\n transcodeImage(\n target: Uint8Array,\n level: number,\n layer: number,\n face: number,\n format: number,\n alphaForOpaque: number,\n channel0: number,\n channel1: number,\n ): boolean;\n close(): void;\n delete(): void;\n}\ninterface BasisModule {\n initializeBasis(): void;\n KTX2File: new (data: Uint8Array) => KTX2File;\n}\n\ntype Factory<T> = (options: { wasmBinary: ArrayBuffer }) => Promise<T>;\n\n/** Loads an Emscripten factory published as a classic script (module workers have no importScripts): imported as a\n * module from a `blob:` URL (a Content Security Policy allowing `blob:` scripts is enough), else evaluated (where\n * `blob:` is refused: `'unsafe-eval'`, see `DecoderUrls`) */\nconst factory = async <T>(url: string, name: string): Promise<Factory<T>> => {\n const source = await (await fetch(url)).text();\n const blob = URL.createObjectURL(new Blob([`${source}\\nexport default ${name};`], { type: 'text/javascript' }));\n\n try {\n const module: unknown = await import(/* @vite-ignore */ blob);\n\n if (isRecord(module) && typeof module.default === 'function') return module.default as Factory<T>;\n } catch {\n // Refused (`blob:` not allowed): evaluated below\n } finally {\n URL.revokeObjectURL(blob);\n }\n\n return new Function(`${source}\\nreturn ${name};`)() as Factory<T>;\n};\n\nconst instantiate = async <T>(base: string, script: string, wasm: string, name: string): Promise<T> => {\n const [create, binary] = await Promise.all([\n factory<T>(`${base}${script}`, name),\n fetch(`${base}${wasm}`).then((r) => r.arrayBuffer()),\n ]);\n\n return create({ wasmBinary: binary });\n};\n\nlet draco: Promise<DracoModule> | undefined;\n/** The full Draco decoder: the glTF build decodes meshes only, not the point clouds */\nlet dracoPoints: Promise<DracoModule> | undefined;\nlet basis: Promise<BasisModule> | undefined;\n\n/** Decodes the Draco primitives of a tile (their points alone for point clouds) */\nexport const decodeDraco = async (urls: DecoderUrls, requests: DracoRequest[]): Promise<DracoGeometry[]> => {\n const meshes = requests.some((r) => !r.points);\n\n if (meshes) {\n draco ??= instantiate<DracoModule>(\n urls.draco,\n 'draco_wasm_wrapper_gltf.js',\n 'draco_decoder_gltf.wasm',\n 'DracoDecoderModule',\n );\n }\n if (requests.some((r) => r.points)) {\n dracoPoints ??= instantiate<DracoModule>(\n urls.draco,\n 'draco_wasm_wrapper.js',\n 'draco_decoder.wasm',\n 'DracoDecoderModule',\n );\n }\n\n const [forMeshes, forPoints] = await Promise.all([meshes ? draco : undefined, dracoPoints]);\n\n return requests.map((request) => {\n const module = request.points ? forPoints : forMeshes;\n\n if (!module) throw new Error('isard: the Draco decoder is not loaded');\n\n const decoder = new module.Decoder();\n const mesh = request.points ? new module.PointCloud() : new module.Mesh();\n\n try {\n const data = new Int8Array(request.data.buffer, request.data.byteOffset, request.data.byteLength);\n const status = request.points\n ? decoder.DecodeArrayToPointCloud(data, data.byteLength, mesh)\n : decoder.DecodeArrayToMesh(data, data.byteLength, mesh);\n\n if (!status.ok()) throw new Error(`Draco: ${status.error_msg()}`);\n\n const floats = (id: number): Float32Array => {\n const attribute = decoder.GetAttributeByUniqueId(mesh, id);\n const count = mesh.num_points() * attribute.num_components();\n const pointer = module._malloc(count * 4);\n\n try {\n decoder.GetAttributeDataArrayForAllPoints(mesh, attribute, module.DT_FLOAT32, count * 4, pointer);\n\n return module.HEAPF32.slice(pointer / 4, pointer / 4 + count);\n } finally {\n module._free(pointer);\n }\n };\n\n if (request.points) {\n const geometry: DracoGeometry = {\n mesh: request.mesh,\n primitive: request.primitive,\n positions: floats(request.position),\n };\n\n if (request.color !== undefined) geometry.colors = floats(request.color);\n if (request.normal !== undefined) geometry.normals = floats(request.normal);\n\n return geometry;\n }\n\n const triangles = (): Uint32Array => {\n const count = mesh.num_faces() * 3;\n const pointer = module._malloc(count * 4);\n\n try {\n decoder.GetTrianglesUInt32Array(mesh, count * 4, pointer);\n\n return module.HEAPU32.slice(pointer / 4, pointer / 4 + count);\n } finally {\n module._free(pointer);\n }\n };\n const indices = triangles();\n const geometry: DracoGeometry = {\n mesh: request.mesh,\n primitive: request.primitive,\n positions: floats(request.position),\n indices,\n };\n\n if (request.uv !== undefined) geometry.uvs = floats(request.uv);\n\n return geometry;\n } finally {\n module.destroy(mesh);\n module.destroy(decoder);\n }\n });\n};\n\n/** Basis target format and WebGL internal format, best first */\nconst target = (formats: TextureFormats, alpha: boolean): { basis: number; gl: number } => {\n if (formats.astc) return { basis: 10, gl: 0x93b0 }; // ASTC 4×4\n if (formats.bptc) return { basis: 6, gl: 0x8e8c }; // BC7\n if (formats.etc) return alpha ? { basis: 1, gl: 0x9278 } : { basis: 0, gl: 0x9274 }; // ETC2 RGBA / ETC1 as ETC2 RGB\n if (formats.s3tc) return alpha ? { basis: 3, gl: 0x83f3 } : { basis: 2, gl: 0x83f0 }; // BC3 / BC1\n\n return { basis: 13, gl: 0x8058 }; // RGBA8, uncompressed\n};\n\n/** Transcodes a KTX2 image for the GPU */\nexport const transcodeKtx2 = async (\n urls: DecoderUrls,\n formats: TextureFormats,\n bytes: Uint8Array,\n): Promise<CompressedTexture> => {\n basis ??= instantiate<BasisModule>(urls.basis, 'basis_transcoder.js', 'basis_transcoder.wasm', 'BASIS').then((m) => {\n m.initializeBasis();\n\n return m;\n });\n\n const module = await basis;\n const file = new module.KTX2File(bytes);\n\n try {\n if (!file.isValid() || !file.startTranscoding()) throw new Error('KTX2: invalid file');\n\n const { basis: format, gl } = target(formats, file.getHasAlpha());\n const levels: CompressedTexture['levels'] = Array.from({ length: file.getLevels() }, (_, level) => {\n const { origWidth: width, origHeight: height } = file.getImageLevelInfo(level, 0, 0);\n const data = new Uint8Array(file.getImageTranscodedSizeInBytes(level, 0, 0, format));\n\n if (!file.transcodeImage(data, level, 0, 0, format, 0, -1, -1)) throw new Error('KTX2: transcoding failed');\n\n return { width, height, data };\n });\n\n return { format: gl, levels };\n } finally {\n file.close();\n file.delete();\n }\n};\n"]}
@@ -15,7 +15,7 @@ export interface Bindings {
15
15
  /** `core`: the engine without 3D Tiles; `full`: with them */
16
16
  export type EngineKind = 'core' | 'full';
17
17
  /** The files a map loads at run time, next to the module unless given elsewhere */
18
- export type AssetFile = 'isard_bg.wasm' | 'isard_core_bg.wasm' | 'isard_points_bg.wasm' | 'isard_tess_bg.wasm' | 'decoder.worker.js' | 'basemap.worker.js';
18
+ export type AssetFile = 'isard_bg.wasm' | 'isard_core_bg.wasm' | 'isard_points_bg.wasm' | 'isard_tess_bg.wasm' | 'isard_grid_bg.wasm' | 'decoder.worker.js' | 'basemap.worker.js';
19
19
  /**
20
20
  * Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's
21
21
  * as `isard/vite` sets it), else next to the module (`import.meta.url`)
@@ -38,6 +38,9 @@ export declare const pointsUrl: (options: Pick<GeoMapOptions, "pointsWasmUrl" |
38
38
  * made ready for the GPU off the main thread): the option, or next to the module; absolute, the workers being
39
39
  * elsewhere */
40
40
  export declare const tessUrl: (options: Pick<GeoMapOptions, "tessWasmUrl" | "assetsUrl">) => string;
41
+ /** Where the workers load the grid module from (`isard_grid_bg.wasm`: GRIB2 and NetCDF files read into grids): the
42
+ * option, or next to the module (absolute: the workers resolve it against their own URL otherwise) */
43
+ export declare const gridUrl: (options: Pick<GeoMapOptions, "gridWasmUrl" | "assetsUrl">) => string;
41
44
  /** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:
42
45
  * false` or 0, or no workers in this environment) */
43
46
  export declare const startTileLoader: (module: WebAssembly.Module, options: Pick<GeoMapOptions, "workers" | "workerUrl" | "decoders" | "pointsWasmUrl" | "assetsUrl">, engine: Engine) => TileLoader | undefined;
@@ -46,6 +46,8 @@ export const assetUrl = (file, explicit, assetsUrl) => {
46
46
  return new URL('./isard_points_bg.wasm', import.meta.url);
47
47
  case 'isard_tess_bg.wasm':
48
48
  return new URL('./isard_tess_bg.wasm', import.meta.url);
49
+ case 'isard_grid_bg.wasm':
50
+ return new URL('./isard_grid_bg.wasm', import.meta.url);
49
51
  case 'decoder.worker.js':
50
52
  return new URL('./decoder.worker.js', import.meta.url);
51
53
  default:
@@ -135,6 +137,13 @@ export const tessUrl = (options) => {
135
137
  const base = typeof document === 'undefined' ? undefined : document.baseURI;
136
138
  return base ? new URL(url, base).href : String(url);
137
139
  };
140
+ /** Where the workers load the grid module from (`isard_grid_bg.wasm`: GRIB2 and NetCDF files read into grids): the
141
+ * option, or next to the module (absolute: the workers resolve it against their own URL otherwise) */
142
+ export const gridUrl = (options) => {
143
+ const url = assetUrl('isard_grid_bg.wasm', options.gridWasmUrl, options.assetsUrl);
144
+ const base = typeof document === 'undefined' ? undefined : document.baseURI;
145
+ return base ? new URL(url, base).href : String(url);
146
+ };
138
147
  /** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:
139
148
  * false` or 0, or no workers in this environment) */
140
149
  export const startTileLoader = (module, options, engine) => {
@@ -1 +1 @@
1
- {"version":3,"file":"engine-loader.js","sourceRoot":"","sources":["../src/engine-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The two builds of the engine, downloaded, compiled and instantiated once per page; the decoding workers of 3D Tiles\n * that run the full one; the engine of a destroyed map.\n */\n\nimport { defaultWorkerCount } from './basemap/workerpool.ts';\nimport { DEFAULT_DECODERS } from './engine/decoders.ts';\nimport { TileLoader } from './engine/loader.ts';\nimport type { GeoMapOptions } from './types.ts';\nimport type { Camera, Engine } from './wasm/isard.js';\n\n/** The class of an engine build: its constructor and its static `customMatrix` (custom layers) */\nexport type EngineClass = (new (\n canvas: HTMLCanvasElement,\n redraw: () => void,\n) => Engine) &\n Pick<typeof Engine, 'customMatrix' | 'geoidHeight'>;\n\n/** An engine loaded: its compiled module and its class */\nexport interface Bindings {\n module: WebAssembly.Module;\n Engine: EngineClass;\n}\n\n/** `core`: the engine without 3D Tiles; `full`: with them */\nexport type EngineKind = 'core' | 'full';\n\n/** The two builds of the engine, each compiled once per page: `core` without 3D Tiles (a third smaller), loaded by\n * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The\n * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */\nconst engines: { core?: Promise<Bindings>; full?: Promise<Bindings> } = {};\n/** The modules compiled (downloaded and compiled off the main thread, not instantiated): `tiles3d: 'preload'`\n * compiles the full engine ahead, its first 3D Tiles layer then only instantiates it */\nconst modules: { core?: Promise<WebAssembly.Module>; full?: Promise<WebAssembly.Module> } = {};\n\n/** @internal Forgets the engines loaded (tests) */\nexport const forgetEngines = (): void => {\n (['core', 'full'] as const).forEach((kind) => {\n delete engines[kind];\n delete modules[kind];\n });\n};\n\n/** The files a map loads at run time, next to the module unless given elsewhere */\nexport type AssetFile =\n | 'isard_bg.wasm'\n | 'isard_core_bg.wasm'\n | 'isard_points_bg.wasm'\n | 'isard_tess_bg.wasm'\n | 'decoder.worker.js'\n | 'basemap.worker.js';\n\n/** The folder the assets are served from for the whole page, as `isard/vite` sets it; undefined: next to the module */\nconst pageAssets = (): string | undefined => {\n const url: unknown = Reflect.get(globalThis, 'isardAssetsUrl');\n\n return typeof url === 'string' ? url : undefined;\n};\n\n/**\n * Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's\n * as `isard/vite` sets it), else next to the module (`import.meta.url`)\n */\nexport const assetUrl = (\n file: AssetFile,\n explicit: string | URL | undefined,\n assetsUrl?: string | URL,\n): string | URL => {\n if (explicit) return explicit;\n\n const folder = assetsUrl ?? pageAssets();\n\n if (folder) {\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n const dir = String(folder).endsWith('/') ? String(folder) : `${String(folder)}/`;\n\n return new URL(file, base ? new URL(dir, base) : dir);\n }\n switch (file) {\n case 'isard_bg.wasm':\n return new URL('./isard_bg.wasm', import.meta.url);\n case 'isard_core_bg.wasm':\n return new URL('./isard_core_bg.wasm', import.meta.url);\n case 'isard_points_bg.wasm':\n return new URL('./isard_points_bg.wasm', import.meta.url);\n case 'isard_tess_bg.wasm':\n return new URL('./isard_tess_bg.wasm', import.meta.url);\n case 'decoder.worker.js':\n return new URL('./decoder.worker.js', import.meta.url);\n default:\n return new URL('./basemap.worker.js', import.meta.url);\n }\n};\n\n/** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */\nexport const engineUrl = (\n kind: EngineKind,\n options: Pick<GeoMapOptions, 'wasmUrl' | 'coreWasmUrl' | 'assetsUrl'>,\n): string | URL => {\n return kind === 'full'\n ? assetUrl('isard_bg.wasm', options.wasmUrl, options.assetsUrl)\n : assetUrl('isard_core_bg.wasm', options.coreWasmUrl, options.assetsUrl);\n};\n\n/** Downloads and compiles a build (once per page, unless it failed: a later call tries again) */\nconst compileEngine = (kind: EngineKind, url: string | URL): Promise<WebAssembly.Module> => {\n const compiled = modules[kind];\n\n if (compiled) return compiled;\n\n const compiling = compile(url).catch((error: unknown) => {\n // A later call tries again (a network error, a wrong URL fixed)\n delete modules[kind];\n throw error;\n });\n\n modules[kind] = compiling;\n\n return compiling;\n};\n\n/** A build compiled and instantiated with its bindings (once per page, unless it failed) */\nexport const loadEngine = (kind: EngineKind, url: string | URL): Promise<Bindings> => {\n const loaded = engines[kind];\n\n if (loaded) return loaded;\n\n const loading = (async () => {\n // The bindings by dynamic import: an application bundles the ones it loads only\n const [module, bindings] = await Promise.all([\n compileEngine(kind, url),\n kind === 'core' ? import('./wasm/isard_core.js') : import('./wasm/isard.js'),\n ]);\n\n await bindings.default({ module_or_path: module });\n\n return { module, Engine: bindings.Engine as unknown as EngineClass };\n })().catch((error: unknown) => {\n delete engines[kind];\n throw error;\n });\n\n engines[kind] = loading;\n\n return loading;\n};\n\n/** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:\n * the map rebuilt on it there, two shorter tasks */\nexport const loadFullEngineLater = (url: string | URL): Promise<Bindings> => {\n return loadEngine('full', url).then(\n (bindings) => new Promise<Bindings>((resolve) => setTimeout(() => resolve(bindings), 0)),\n );\n};\n\n/** Downloads and compiles the full engine when the page is idle, without running it; a failure is left to the first\n * 3D Tiles layer, which tries again */\nexport const preloadFullEngine = (url: string | URL, wanted: () => boolean): void => {\n const start = () => {\n if (wanted()) compileEngine('full', url).catch(() => undefined);\n };\n\n if (typeof requestIdleCallback === 'function') requestIdleCallback(start, { timeout: 2000 });\n else setTimeout(start, 0);\n};\n\nconst compile = async (url: string | URL): Promise<WebAssembly.Module> => {\n const response = await fetch(url);\n\n if (!response.ok) throw new Error(`isard: failed to load the engine from ${url}: ${response.status}`);\n try {\n return await WebAssembly.compileStreaming(response.clone());\n } catch {\n // Servers that do not send application/wasm\n return WebAssembly.compile(await response.arrayBuffer());\n }\n};\n\n/** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next\n * to the module; absolute, the workers being elsewhere */\nexport const pointsUrl = (options: Pick<GeoMapOptions, 'pointsWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_points_bg.wasm', options.pointsWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** Where the basemap workers load the tessellation module from (`isard_tess_bg.wasm`: the vector tiles of `vectors()`\n * made ready for the GPU off the main thread): the option, or next to the module; absolute, the workers being\n * elsewhere */\nexport const tessUrl = (options: Pick<GeoMapOptions, 'tessWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_tess_bg.wasm', options.tessWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:\n * false` or 0, or no workers in this environment) */\nexport const startTileLoader = (\n module: WebAssembly.Module,\n options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'>,\n engine: Engine,\n): TileLoader | undefined => {\n const { workers: count, workerUrl, decoders } = options;\n const workers = count ?? defaultWorkerCount();\n\n if (workers === false || workers <= 0 || typeof Worker === 'undefined') return undefined;\n\n return new TileLoader(\n module,\n assetUrl('decoder.worker.js', workerUrl, options.assetsUrl),\n workers,\n { ...DEFAULT_DECODERS, ...decoders },\n engine.textureFormats(),\n pointsUrl(options),\n );\n};\n\n/** The engine of a destroyed map: every method a no-op returning undefined, but the camera (the last one) and the\n * bounds, which late callers read */\nexport const destroyedEngine = (camera: Camera): Engine => {\n return new Proxy(\n {},\n {\n get: (_, name) => {\n if (name === 'camera') return () => camera;\n if (name === 'bounds') return () => Float64Array.of(-180, -85, 180, 85);\n\n return () => undefined;\n },\n },\n ) as Engine;\n};\n"]}
1
+ {"version":3,"file":"engine-loader.js","sourceRoot":"","sources":["../src/engine-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The two builds of the engine, downloaded, compiled and instantiated once per page; the decoding workers of 3D Tiles\n * that run the full one; the engine of a destroyed map.\n */\n\nimport { defaultWorkerCount } from './basemap/workerpool.ts';\nimport { DEFAULT_DECODERS } from './engine/decoders.ts';\nimport { TileLoader } from './engine/loader.ts';\nimport type { GeoMapOptions } from './types.ts';\nimport type { Camera, Engine } from './wasm/isard.js';\n\n/** The class of an engine build: its constructor and its static `customMatrix` (custom layers) */\nexport type EngineClass = (new (\n canvas: HTMLCanvasElement,\n redraw: () => void,\n) => Engine) &\n Pick<typeof Engine, 'customMatrix' | 'geoidHeight'>;\n\n/** An engine loaded: its compiled module and its class */\nexport interface Bindings {\n module: WebAssembly.Module;\n Engine: EngineClass;\n}\n\n/** `core`: the engine without 3D Tiles; `full`: with them */\nexport type EngineKind = 'core' | 'full';\n\n/** The two builds of the engine, each compiled once per page: `core` without 3D Tiles (a third smaller), loaded by\n * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The\n * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */\nconst engines: { core?: Promise<Bindings>; full?: Promise<Bindings> } = {};\n/** The modules compiled (downloaded and compiled off the main thread, not instantiated): `tiles3d: 'preload'`\n * compiles the full engine ahead, its first 3D Tiles layer then only instantiates it */\nconst modules: { core?: Promise<WebAssembly.Module>; full?: Promise<WebAssembly.Module> } = {};\n\n/** @internal Forgets the engines loaded (tests) */\nexport const forgetEngines = (): void => {\n (['core', 'full'] as const).forEach((kind) => {\n delete engines[kind];\n delete modules[kind];\n });\n};\n\n/** The files a map loads at run time, next to the module unless given elsewhere */\nexport type AssetFile =\n | 'isard_bg.wasm'\n | 'isard_core_bg.wasm'\n | 'isard_points_bg.wasm'\n | 'isard_tess_bg.wasm'\n | 'isard_grid_bg.wasm'\n | 'decoder.worker.js'\n | 'basemap.worker.js';\n\n/** The folder the assets are served from for the whole page, as `isard/vite` sets it; undefined: next to the module */\nconst pageAssets = (): string | undefined => {\n const url: unknown = Reflect.get(globalThis, 'isardAssetsUrl');\n\n return typeof url === 'string' ? url : undefined;\n};\n\n/**\n * Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's\n * as `isard/vite` sets it), else next to the module (`import.meta.url`)\n */\nexport const assetUrl = (\n file: AssetFile,\n explicit: string | URL | undefined,\n assetsUrl?: string | URL,\n): string | URL => {\n if (explicit) return explicit;\n\n const folder = assetsUrl ?? pageAssets();\n\n if (folder) {\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n const dir = String(folder).endsWith('/') ? String(folder) : `${String(folder)}/`;\n\n return new URL(file, base ? new URL(dir, base) : dir);\n }\n switch (file) {\n case 'isard_bg.wasm':\n return new URL('./isard_bg.wasm', import.meta.url);\n case 'isard_core_bg.wasm':\n return new URL('./isard_core_bg.wasm', import.meta.url);\n case 'isard_points_bg.wasm':\n return new URL('./isard_points_bg.wasm', import.meta.url);\n case 'isard_tess_bg.wasm':\n return new URL('./isard_tess_bg.wasm', import.meta.url);\n case 'isard_grid_bg.wasm':\n return new URL('./isard_grid_bg.wasm', import.meta.url);\n case 'decoder.worker.js':\n return new URL('./decoder.worker.js', import.meta.url);\n default:\n return new URL('./basemap.worker.js', import.meta.url);\n }\n};\n\n/** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */\nexport const engineUrl = (\n kind: EngineKind,\n options: Pick<GeoMapOptions, 'wasmUrl' | 'coreWasmUrl' | 'assetsUrl'>,\n): string | URL => {\n return kind === 'full'\n ? assetUrl('isard_bg.wasm', options.wasmUrl, options.assetsUrl)\n : assetUrl('isard_core_bg.wasm', options.coreWasmUrl, options.assetsUrl);\n};\n\n/** Downloads and compiles a build (once per page, unless it failed: a later call tries again) */\nconst compileEngine = (kind: EngineKind, url: string | URL): Promise<WebAssembly.Module> => {\n const compiled = modules[kind];\n\n if (compiled) return compiled;\n\n const compiling = compile(url).catch((error: unknown) => {\n // A later call tries again (a network error, a wrong URL fixed)\n delete modules[kind];\n throw error;\n });\n\n modules[kind] = compiling;\n\n return compiling;\n};\n\n/** A build compiled and instantiated with its bindings (once per page, unless it failed) */\nexport const loadEngine = (kind: EngineKind, url: string | URL): Promise<Bindings> => {\n const loaded = engines[kind];\n\n if (loaded) return loaded;\n\n const loading = (async () => {\n // The bindings by dynamic import: an application bundles the ones it loads only\n const [module, bindings] = await Promise.all([\n compileEngine(kind, url),\n kind === 'core' ? import('./wasm/isard_core.js') : import('./wasm/isard.js'),\n ]);\n\n await bindings.default({ module_or_path: module });\n\n return { module, Engine: bindings.Engine as unknown as EngineClass };\n })().catch((error: unknown) => {\n delete engines[kind];\n throw error;\n });\n\n engines[kind] = loading;\n\n return loading;\n};\n\n/** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:\n * the map rebuilt on it there, two shorter tasks */\nexport const loadFullEngineLater = (url: string | URL): Promise<Bindings> => {\n return loadEngine('full', url).then(\n (bindings) => new Promise<Bindings>((resolve) => setTimeout(() => resolve(bindings), 0)),\n );\n};\n\n/** Downloads and compiles the full engine when the page is idle, without running it; a failure is left to the first\n * 3D Tiles layer, which tries again */\nexport const preloadFullEngine = (url: string | URL, wanted: () => boolean): void => {\n const start = () => {\n if (wanted()) compileEngine('full', url).catch(() => undefined);\n };\n\n if (typeof requestIdleCallback === 'function') requestIdleCallback(start, { timeout: 2000 });\n else setTimeout(start, 0);\n};\n\nconst compile = async (url: string | URL): Promise<WebAssembly.Module> => {\n const response = await fetch(url);\n\n if (!response.ok) throw new Error(`isard: failed to load the engine from ${url}: ${response.status}`);\n try {\n return await WebAssembly.compileStreaming(response.clone());\n } catch {\n // Servers that do not send application/wasm\n return WebAssembly.compile(await response.arrayBuffer());\n }\n};\n\n/** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next\n * to the module; absolute, the workers being elsewhere */\nexport const pointsUrl = (options: Pick<GeoMapOptions, 'pointsWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_points_bg.wasm', options.pointsWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** Where the basemap workers load the tessellation module from (`isard_tess_bg.wasm`: the vector tiles of `vectors()`\n * made ready for the GPU off the main thread): the option, or next to the module; absolute, the workers being\n * elsewhere */\nexport const tessUrl = (options: Pick<GeoMapOptions, 'tessWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_tess_bg.wasm', options.tessWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** Where the workers load the grid module from (`isard_grid_bg.wasm`: GRIB2 and NetCDF files read into grids): the\n * option, or next to the module (absolute: the workers resolve it against their own URL otherwise) */\nexport const gridUrl = (options: Pick<GeoMapOptions, 'gridWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_grid_bg.wasm', options.gridWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:\n * false` or 0, or no workers in this environment) */\nexport const startTileLoader = (\n module: WebAssembly.Module,\n options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'>,\n engine: Engine,\n): TileLoader | undefined => {\n const { workers: count, workerUrl, decoders } = options;\n const workers = count ?? defaultWorkerCount();\n\n if (workers === false || workers <= 0 || typeof Worker === 'undefined') return undefined;\n\n return new TileLoader(\n module,\n assetUrl('decoder.worker.js', workerUrl, options.assetsUrl),\n workers,\n { ...DEFAULT_DECODERS, ...decoders },\n engine.textureFormats(),\n pointsUrl(options),\n );\n};\n\n/** The engine of a destroyed map: every method a no-op returning undefined, but the camera (the last one) and the\n * bounds, which late callers read */\nexport const destroyedEngine = (camera: Camera): Engine => {\n return new Proxy(\n {},\n {\n get: (_, name) => {\n if (name === 'camera') return () => camera;\n if (name === 'bounds') return () => Float64Array.of(-180, -85, 180, 85);\n\n return () => undefined;\n },\n },\n ) as Engine;\n};\n"]}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The grid module (`isard_grid_bg.wasm`) as the workers (and the page without them) run it: a GRIB2 or NetCDF file's
3
+ * bytes to its grids' descriptions and values. Nothing of the page: the basemap workers import it.
4
+ */
5
+ /** A grid's description as the grid module gives it (JSON): a grid without its values */
6
+ export interface GridDescription {
7
+ name: string;
8
+ standardName: string | null;
9
+ units: string | null;
10
+ level: {
11
+ kind: string;
12
+ value: number | null;
13
+ } | null;
14
+ time: number | null;
15
+ width: number;
16
+ height: number;
17
+ bounds: (number | null)[];
18
+ }
19
+ /** The flows of a city's streets for a wind of 1 m/s towards the east and one towards the north, their east and north
20
+ * velocities in each of `width` × `height` cells */
21
+ export interface StreetFlows {
22
+ eastU: Float32Array;
23
+ eastV: Float32Array;
24
+ northU: Float32Array;
25
+ northV: Float32Array;
26
+ }
27
+ /**
28
+ * The streets' flows round buildings (their rings in cells from the north-west corner: `points` interleaved, the
29
+ * first point of each ring, the first ring of each polygon, each with its end), by the grid module (`module`), after
30
+ * `iterations` sweeps
31
+ */
32
+ export declare const streetFlows: (buildings: {
33
+ points: Float64Array;
34
+ ringStart: Uint32Array;
35
+ polygonStart: Uint32Array;
36
+ }, width: number, height: number, iterations: number, module: string | URL) => Promise<StreetFlows>;
37
+ /**
38
+ * The grids of a GRIB2 or classic NetCDF file's bytes, read by the grid module (`module`: its URL, loaded on first
39
+ * use): their descriptions and values, apart (the values to transfer from a worker)
40
+ */
41
+ export declare const decodeGrids: (bytes: Uint8Array, module: string | URL) => Promise<{
42
+ grids: GridDescription[];
43
+ values: Float32Array[];
44
+ }>;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The grid module (`isard_grid_bg.wasm`) as the workers (and the page without them) run it: a GRIB2 or NetCDF file's
3
+ * bytes to its grids' descriptions and values. Nothing of the page: the basemap workers import it.
4
+ */
5
+ import initGrid, { readGrids, streetFlow } from './wasm/isard_grid.js';
6
+ /** The grid module, loaded once (from `module`), again after a failure */
7
+ const grid = {};
8
+ /** The grid module loaded from `module`, once (again after a failure) */
9
+ const gridModule = async (module) => {
10
+ const ready = grid.ready ?? initGrid({ module_or_path: module });
11
+ grid.ready = ready;
12
+ await ready.catch((error) => {
13
+ grid.ready = undefined;
14
+ throw error;
15
+ });
16
+ };
17
+ /**
18
+ * The streets' flows round buildings (their rings in cells from the north-west corner: `points` interleaved, the
19
+ * first point of each ring, the first ring of each polygon, each with its end), by the grid module (`module`), after
20
+ * `iterations` sweeps
21
+ */
22
+ export const streetFlows = async (buildings, width, height, iterations, module) => {
23
+ await gridModule(module);
24
+ const flow = streetFlow(buildings.points, buildings.ringStart, buildings.polygonStart, width, height, iterations);
25
+ try {
26
+ return { eastU: flow.eastU(), eastV: flow.eastV(), northU: flow.northU(), northV: flow.northV() };
27
+ }
28
+ finally {
29
+ flow.free();
30
+ }
31
+ };
32
+ /** Whether a value is a grid's description as the grid module writes it */
33
+ const isDescription = (value) => typeof value === 'object' &&
34
+ value !== null &&
35
+ 'name' in value &&
36
+ 'width' in value &&
37
+ 'height' in value &&
38
+ 'bounds' in value &&
39
+ Array.isArray(value.bounds);
40
+ /**
41
+ * The grids of a GRIB2 or classic NetCDF file's bytes, read by the grid module (`module`: its URL, loaded on first
42
+ * use): their descriptions and values, apart (the values to transfer from a worker)
43
+ */
44
+ export const decodeGrids = async (bytes, module) => {
45
+ await gridModule(module);
46
+ const set = readGrids(bytes);
47
+ try {
48
+ const grids = [];
49
+ const values = [];
50
+ for (let i = 0; i < set.count(); i++) {
51
+ const description = JSON.parse(set.meta(i));
52
+ if (!isDescription(description))
53
+ throw new Error('isard: a grid without its description');
54
+ grids.push(description);
55
+ values.push(set.values(i));
56
+ }
57
+ return { grids, values };
58
+ }
59
+ finally {
60
+ set.free();
61
+ }
62
+ };
63
+ //# sourceMappingURL=grid-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-module.js","sourceRoot":"","sources":["../src/grid-module.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,QAAQ,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAcvE,0EAA0E;AAC1E,MAAM,IAAI,GAA6C,EAAE,CAAC;AAE1D,yEAAyE;AACzE,MAAM,UAAU,GAAG,KAAK,EAAE,MAAoB,EAAiB,EAAE;IAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;IAEjE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACnB,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACnC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAWF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC9B,SAAsF,EACtF,KAAa,EACb,MAAc,EACd,UAAkB,EAClB,MAAoB,EACE,EAAE;IACxB,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;IAEzB,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAElH,IAAI,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IACpG,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,aAAa,GAAG,CAAC,KAAc,EAA4B,EAAE,CACjE,OAAO,KAAK,KAAK,QAAQ;IACzB,KAAK,KAAK,IAAI;IACd,MAAM,IAAI,KAAK;IACf,OAAO,IAAI,KAAK;IAChB,QAAQ,IAAI,KAAK;IACjB,QAAQ,IAAI,KAAK;IACjB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAE9B;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC9B,KAAiB,EACjB,MAAoB,EAC2C,EAAE;IACjE,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;IAEzB,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,KAAK,GAAsB,EAAE,CAAC;QACpC,MAAM,MAAM,GAAmB,EAAE,CAAC;QAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,MAAM,WAAW,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAErD,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC1F,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC3B,CAAC;YAAS,CAAC;QACT,GAAG,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;AACH,CAAC,CAAC","sourcesContent":["/**\n * The grid module (`isard_grid_bg.wasm`) as the workers (and the page without them) run it: a GRIB2 or NetCDF file's\n * bytes to its grids' descriptions and values. Nothing of the page: the basemap workers import it.\n */\n\nimport initGrid, { readGrids, streetFlow } from './wasm/isard_grid.js';\n\n/** A grid's description as the grid module gives it (JSON): a grid without its values */\nexport interface GridDescription {\n name: string;\n standardName: string | null;\n units: string | null;\n level: { kind: string; value: number | null } | null;\n time: number | null;\n width: number;\n height: number;\n bounds: (number | null)[];\n}\n\n/** The grid module, loaded once (from `module`), again after a failure */\nconst grid: { ready?: Promise<unknown> | undefined } = {};\n\n/** The grid module loaded from `module`, once (again after a failure) */\nconst gridModule = async (module: string | URL): Promise<void> => {\n const ready = grid.ready ?? initGrid({ module_or_path: module });\n\n grid.ready = ready;\n await ready.catch((error: unknown) => {\n grid.ready = undefined;\n throw error;\n });\n};\n\n/** The flows of a city's streets for a wind of 1 m/s towards the east and one towards the north, their east and north\n * velocities in each of `width` × `height` cells */\nexport interface StreetFlows {\n eastU: Float32Array;\n eastV: Float32Array;\n northU: Float32Array;\n northV: Float32Array;\n}\n\n/**\n * The streets' flows round buildings (their rings in cells from the north-west corner: `points` interleaved, the\n * first point of each ring, the first ring of each polygon, each with its end), by the grid module (`module`), after\n * `iterations` sweeps\n */\nexport const streetFlows = async (\n buildings: { points: Float64Array; ringStart: Uint32Array; polygonStart: Uint32Array },\n width: number,\n height: number,\n iterations: number,\n module: string | URL,\n): Promise<StreetFlows> => {\n await gridModule(module);\n\n const flow = streetFlow(buildings.points, buildings.ringStart, buildings.polygonStart, width, height, iterations);\n\n try {\n return { eastU: flow.eastU(), eastV: flow.eastV(), northU: flow.northU(), northV: flow.northV() };\n } finally {\n flow.free();\n }\n};\n\n/** Whether a value is a grid's description as the grid module writes it */\nconst isDescription = (value: unknown): value is GridDescription =>\n typeof value === 'object' &&\n value !== null &&\n 'name' in value &&\n 'width' in value &&\n 'height' in value &&\n 'bounds' in value &&\n Array.isArray(value.bounds);\n\n/**\n * The grids of a GRIB2 or classic NetCDF file's bytes, read by the grid module (`module`: its URL, loaded on first\n * use): their descriptions and values, apart (the values to transfer from a worker)\n */\nexport const decodeGrids = async (\n bytes: Uint8Array,\n module: string | URL,\n): Promise<{ grids: GridDescription[]; values: Float32Array[] }> => {\n await gridModule(module);\n\n const set = readGrids(bytes);\n\n try {\n const grids: GridDescription[] = [];\n const values: Float32Array[] = [];\n\n for (let i = 0; i < set.count(); i++) {\n const description: unknown = JSON.parse(set.meta(i));\n\n if (!isDescription(description)) throw new Error('isard: a grid without its description');\n grids.push(description);\n values.push(set.values(i));\n }\n\n return { grids, values };\n } finally {\n set.free();\n }\n};\n"]}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Gridded data: the fields of a weather or ocean model read from their files (GRIB2, classic NetCDF) into grids of
3
+ * longitudes and latitudes, by the grid module (`isard_grid_bg.wasm`) in a worker; the wind's components paired into
4
+ * the fields of a flow layer.
5
+ */
6
+ import type { GridDescription } from './grid-module.ts';
7
+ import type { TimedField } from './layers/flow.ts';
8
+ /**
9
+ * A field on a grid of longitudes and latitudes: `width` × `height` values, row after row from north to south, each
10
+ * from west to east (not a number where there is none), whatever the order of the file
11
+ */
12
+ export interface Grid {
13
+ /** A GRIB2 parameter's short name (`UGRD`, `VGRD`, `TMP`…), a NetCDF variable's name */
14
+ name: string;
15
+ /** Its CF standard name (`eastward_wind`…), when the file gives one or the parameter is known */
16
+ standardName?: string;
17
+ units?: string;
18
+ /** Its level: kind (`height above ground`, `isobaric`, a NetCDF dimension's name…) and value (metres, pascals…) */
19
+ level?: {
20
+ kind: string;
21
+ value: number;
22
+ };
23
+ /** When it is valid (milliseconds since 1970, UTC) */
24
+ time?: number;
25
+ width: number;
26
+ height: number;
27
+ /** The longitudes and latitudes of the corner points: west, south, east, north (degrees) */
28
+ bounds: [west: number, south: number, east: number, north: number];
29
+ values: Float32Array;
30
+ }
31
+ /** A grid from its description and values */
32
+ export declare const gridOf: (d: GridDescription, values: Float32Array) => Grid;
33
+ /**
34
+ * The fields of a flow layer from grids: their east and north components (a wind's, a current's: by their standard
35
+ * names `eastward_wind`… or names `UGRD`, `u10`…; `u` and `v` to name them) paired by time and level, at `level` (by
36
+ * default the first one found: a model's 10 m wind), sorted by time
37
+ */
38
+ export declare const windFields: (grids: readonly Grid[], options?: {
39
+ u?: string;
40
+ v?: string;
41
+ level?: {
42
+ kind: string;
43
+ value: number;
44
+ };
45
+ }) => TimedField[];
46
+ /**
47
+ * A wind at a place and a time (east and north, m/s) from a model's fields (`windFields`): between two of its hours, the
48
+ * mix of the two; undefined outside the fields or where they have none. The wind far away of a city's streets
49
+ * (`vectorTiles().streetWind`), as a clock runs
50
+ */
51
+ export declare const windAt: (fields: readonly TimedField[], time: Date | number, [lon, lat]: [lon: number, lat: number]) => [u: number, v: number] | undefined;
package/dist/grids.js ADDED
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Gridded data: the fields of a weather or ocean model read from their files (GRIB2, classic NetCDF) into grids of
3
+ * longitudes and latitudes, by the grid module (`isard_grid_bg.wasm`) in a worker; the wind's components paired into
4
+ * the fields of a flow layer.
5
+ */
6
+ /** A grid from its description and values */
7
+ export const gridOf = (d, values) => {
8
+ const [west = 0, south = 0, east = 0, north = 0] = d.bounds.map((b) => b ?? 0);
9
+ return {
10
+ name: d.name,
11
+ ...(d.standardName ? { standardName: d.standardName } : {}),
12
+ ...(d.units ? { units: d.units } : {}),
13
+ ...(d.level && d.level.value !== null ? { level: { kind: d.level.kind, value: d.level.value } } : {}),
14
+ ...(d.time !== null ? { time: d.time } : {}),
15
+ width: d.width,
16
+ height: d.height,
17
+ bounds: [west, south, east, north],
18
+ values,
19
+ };
20
+ };
21
+ const EAST = new Set(['eastward_wind', 'eastward_sea_water_velocity', 'UGRD', 'UOGRD', 'u10', 'u', 'uo', 'ugrd']);
22
+ const NORTH = new Set(['northward_wind', 'northward_sea_water_velocity', 'VGRD', 'VOGRD', 'v10', 'v', 'vo', 'vgrd']);
23
+ /** Whether a grid is a velocity's east (or north) component: by its standard name, else its name */
24
+ const isComponent = (g, names, name) => name ? g.name === name : names.has(g.standardName ?? '') || names.has(g.name);
25
+ /** A grid's level as a key */
26
+ const levelKey = (g) => (g.level ? `${g.level.kind} ${g.level.value}` : '');
27
+ /**
28
+ * The fields of a flow layer from grids: their east and north components (a wind's, a current's: by their standard
29
+ * names `eastward_wind`… or names `UGRD`, `u10`…; `u` and `v` to name them) paired by time and level, at `level` (by
30
+ * default the first one found: a model's 10 m wind), sorted by time
31
+ */
32
+ export const windFields = (grids, options = {}) => {
33
+ const easts = grids.filter((g) => isComponent(g, EAST, options.u));
34
+ const first = easts[0];
35
+ const chosen = options.level && `${options.level.kind} ${options.level.value}`;
36
+ const level = chosen ?? (first ? levelKey(first) : '');
37
+ return easts
38
+ .filter((u) => levelKey(u) === level)
39
+ .flatMap((u) => {
40
+ const v = grids.find((g) => isComponent(g, NORTH, options.v) &&
41
+ g.time === u.time &&
42
+ levelKey(g) === level &&
43
+ g.width === u.width &&
44
+ g.height === u.height);
45
+ if (!v)
46
+ return [];
47
+ const field = { width: u.width, height: u.height, u: u.values, v: v.values, bounds: u.bounds };
48
+ return [{ time: u.time ?? 0, field }];
49
+ })
50
+ .sort((a, b) => Number(a.time) - Number(b.time));
51
+ };
52
+ /** A field's value at a place (bilinear; round the world for a global grid), undefined outside it or where it has none */
53
+ const sample = (field, lon, lat) => {
54
+ const { width, height, u, v, bounds } = field;
55
+ const [west, south, east, north] = bounds;
56
+ const step = (east - west) / Math.max(1, width - 1);
57
+ const wraps = Math.abs(east - west + step - 360) < step / 2;
58
+ const fx = wraps ? ((((lon - west) % 360) + 360) % 360) / step : (lon - west) / step;
59
+ const fy = ((north - lat) / (north - south)) * (height - 1);
60
+ if (fy < 0 || fy > height - 1 || fx < 0 || fx > (wraps ? width : width - 1))
61
+ return undefined;
62
+ const [x0, y0] = [Math.floor(fx), Math.floor(fy)];
63
+ const [tx, ty] = [fx - x0, fy - y0];
64
+ const column = (c) => (wraps ? c % width : Math.min(c, width - 1));
65
+ const at = (grid, r, c) => grid[Math.min(r, height - 1) * width + column(c)] ?? NaN;
66
+ const mix = (grid) => (at(grid, y0, x0) * (1 - tx) + at(grid, y0, x0 + 1) * tx) * (1 - ty) +
67
+ (at(grid, y0 + 1, x0) * (1 - tx) + at(grid, y0 + 1, x0 + 1) * tx) * ty;
68
+ const [a, b] = [mix(u), mix(v)];
69
+ return Number.isFinite(a) && Number.isFinite(b) ? [a, b] : undefined;
70
+ };
71
+ /**
72
+ * A wind at a place and a time (east and north, m/s) from a model's fields (`windFields`): between two of its hours, the
73
+ * mix of the two; undefined outside the fields or where they have none. The wind far away of a city's streets
74
+ * (`vectorTiles().streetWind`), as a clock runs
75
+ */
76
+ export const windAt = (fields, time, [lon, lat]) => {
77
+ const t = Number(time);
78
+ const sorted = [...fields].sort((a, b) => Number(a.time) - Number(b.time));
79
+ const after = sorted.findIndex((f) => Number(f.time) > t);
80
+ const [a, b] = after <= 0 ? [sorted[after < 0 ? sorted.length - 1 : 0], undefined] : [sorted[after - 1], sorted[after]];
81
+ const at = a && sample(a.field, lon, lat);
82
+ if (!at || !b)
83
+ return at;
84
+ const next = sample(b.field, lon, lat);
85
+ const k = (t - Number(a.time)) / (Number(b.time) - Number(a.time));
86
+ return next ? [at[0] + (next[0] - at[0]) * k, at[1] + (next[1] - at[1]) * k] : at;
87
+ };
88
+ //# sourceMappingURL=grids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grids.js","sourceRoot":"","sources":["../src/grids.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Gridded data: the fields of a weather or ocean model read from their files (GRIB2, classic NetCDF) into grids of\n * longitudes and latitudes, by the grid module (`isard_grid_bg.wasm`) in a worker; the wind's components paired into\n * the fields of a flow layer.\n */\n\nimport type { GridDescription } from './grid-module.ts';\nimport type { FlowField, TimedField } from './layers/flow.ts';\n\n/**\n * A field on a grid of longitudes and latitudes: `width` × `height` values, row after row from north to south, each\n * from west to east (not a number where there is none), whatever the order of the file\n */\nexport interface Grid {\n /** A GRIB2 parameter's short name (`UGRD`, `VGRD`, `TMP`…), a NetCDF variable's name */\n name: string;\n /** Its CF standard name (`eastward_wind`…), when the file gives one or the parameter is known */\n standardName?: string;\n units?: string;\n /** Its level: kind (`height above ground`, `isobaric`, a NetCDF dimension's name…) and value (metres, pascals…) */\n level?: { kind: string; value: number };\n /** When it is valid (milliseconds since 1970, UTC) */\n time?: number;\n width: number;\n height: number;\n /** The longitudes and latitudes of the corner points: west, south, east, north (degrees) */\n bounds: [west: number, south: number, east: number, north: number];\n values: Float32Array;\n}\n\n/** A grid from its description and values */\nexport const gridOf = (d: GridDescription, values: Float32Array): Grid => {\n const [west = 0, south = 0, east = 0, north = 0] = d.bounds.map((b) => b ?? 0);\n\n return {\n name: d.name,\n ...(d.standardName ? { standardName: d.standardName } : {}),\n ...(d.units ? { units: d.units } : {}),\n ...(d.level && d.level.value !== null ? { level: { kind: d.level.kind, value: d.level.value } } : {}),\n ...(d.time !== null ? { time: d.time } : {}),\n width: d.width,\n height: d.height,\n bounds: [west, south, east, north],\n values,\n };\n};\n\nconst EAST = new Set(['eastward_wind', 'eastward_sea_water_velocity', 'UGRD', 'UOGRD', 'u10', 'u', 'uo', 'ugrd']);\nconst NORTH = new Set(['northward_wind', 'northward_sea_water_velocity', 'VGRD', 'VOGRD', 'v10', 'v', 'vo', 'vgrd']);\n\n/** Whether a grid is a velocity's east (or north) component: by its standard name, else its name */\nconst isComponent = (g: Grid, names: ReadonlySet<string>, name: string | undefined) =>\n name ? g.name === name : names.has(g.standardName ?? '') || names.has(g.name);\n\n/** A grid's level as a key */\nconst levelKey = (g: Grid) => (g.level ? `${g.level.kind} ${g.level.value}` : '');\n\n/**\n * The fields of a flow layer from grids: their east and north components (a wind's, a current's: by their standard\n * names `eastward_wind`… or names `UGRD`, `u10`…; `u` and `v` to name them) paired by time and level, at `level` (by\n * default the first one found: a model's 10 m wind), sorted by time\n */\nexport const windFields = (\n grids: readonly Grid[],\n options: { u?: string; v?: string; level?: { kind: string; value: number } } = {},\n): TimedField[] => {\n const easts = grids.filter((g) => isComponent(g, EAST, options.u));\n const first = easts[0];\n const chosen = options.level && `${options.level.kind} ${options.level.value}`;\n const level = chosen ?? (first ? levelKey(first) : '');\n\n return easts\n .filter((u) => levelKey(u) === level)\n .flatMap((u): TimedField[] => {\n const v = grids.find(\n (g) =>\n isComponent(g, NORTH, options.v) &&\n g.time === u.time &&\n levelKey(g) === level &&\n g.width === u.width &&\n g.height === u.height,\n );\n\n if (!v) return [];\n\n const field: FlowField = { width: u.width, height: u.height, u: u.values, v: v.values, bounds: u.bounds };\n\n return [{ time: u.time ?? 0, field }];\n })\n .sort((a, b) => Number(a.time) - Number(b.time));\n};\n\n/** A field's value at a place (bilinear; round the world for a global grid), undefined outside it or where it has none */\nconst sample = (field: FlowField, lon: number, lat: number): [number, number] | undefined => {\n const { width, height, u, v, bounds } = field;\n const [west, south, east, north] = bounds;\n const step = (east - west) / Math.max(1, width - 1);\n const wraps = Math.abs(east - west + step - 360) < step / 2;\n const fx = wraps ? ((((lon - west) % 360) + 360) % 360) / step : (lon - west) / step;\n const fy = ((north - lat) / (north - south)) * (height - 1);\n\n if (fy < 0 || fy > height - 1 || fx < 0 || fx > (wraps ? width : width - 1)) return undefined;\n\n const [x0, y0] = [Math.floor(fx), Math.floor(fy)];\n const [tx, ty] = [fx - x0, fy - y0];\n const column = (c: number) => (wraps ? c % width : Math.min(c, width - 1));\n const at = (grid: FlowField['u'], r: number, c: number) => grid[Math.min(r, height - 1) * width + column(c)] ?? NaN;\n const mix = (grid: FlowField['u']) =>\n (at(grid, y0, x0) * (1 - tx) + at(grid, y0, x0 + 1) * tx) * (1 - ty) +\n (at(grid, y0 + 1, x0) * (1 - tx) + at(grid, y0 + 1, x0 + 1) * tx) * ty;\n const [a, b] = [mix(u), mix(v)];\n\n return Number.isFinite(a) && Number.isFinite(b) ? [a, b] : undefined;\n};\n\n/**\n * A wind at a place and a time (east and north, m/s) from a model's fields (`windFields`): between two of its hours, the\n * mix of the two; undefined outside the fields or where they have none. The wind far away of a city's streets\n * (`vectorTiles().streetWind`), as a clock runs\n */\nexport const windAt = (\n fields: readonly TimedField[],\n time: Date | number,\n [lon, lat]: [lon: number, lat: number],\n): [u: number, v: number] | undefined => {\n const t = Number(time);\n const sorted = [...fields].sort((a, b) => Number(a.time) - Number(b.time));\n const after = sorted.findIndex((f) => Number(f.time) > t);\n const [a, b] =\n after <= 0 ? [sorted[after < 0 ? sorted.length - 1 : 0], undefined] : [sorted[after - 1], sorted[after]];\n const at = a && sample(a.field, lon, lat);\n\n if (!at || !b) return at;\n\n const next = sample(b.field, lon, lat);\n const k = (t - Number(a.time)) / (Number(b.time) - Number(a.time));\n\n return next ? [at[0] + (next[0] - at[0]) * k, at[1] + (next[1] - at[1]) * k] : at;\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -17,6 +17,12 @@ export { PMTiles, type PmtilesEntry, type PmtilesHeader, type PmtilesTileType, t
17
17
  export { basicStyle, type PmtilesOptions } from './basemap/pmtileslayer.ts';
18
18
  export { type TreeColors, treeModel } from './basemap/trees.ts';
19
19
  export type { CandidateIcon, CandidateOverlap, Json, LabelCandidate, RasterSource, Style, StyleLayer, } from './basemap/vectorstyle.ts';
20
+ export type { VectorExtrusionOptions } from './basemap/vectortiles/extrusions.ts';
21
+ export type { LabelsOptions } from './basemap/vectortiles/labels.ts';
22
+ export type { StreetWindLayer, StreetWindOptions } from './basemap/vectortiles/street-wind.ts';
23
+ export type { LoadedStyle } from './basemap/vectortiles/style.ts';
24
+ export type { TreesOptions } from './basemap/vectortiles/trees.ts';
25
+ export type { VectorsOptions } from './basemap/vectortiles/vectors.ts';
20
26
  export type { VectorTilesOptions } from './basemap/vectortiles.ts';
21
27
  export { OPENFREEMAP_STYLES, PLAN_STYLES, VectorTiles } from './basemap/vectortiles.ts';
22
28
  export { parseWmtsGrid, wmtsGrid } from './basemap/wmts.ts';
@@ -26,11 +32,14 @@ export { parseKml } from './data/kml.ts';
26
32
  export { parseTopoJson, type TopoGeometry, type Topology } from './data/topojson.ts';
27
33
  export type { DecoderUrls } from './engine/decoders.ts';
28
34
  export { setRequestHeaders } from './engine/requests.ts';
29
- export { BATIMENTS_3D_URL, type BdTopoBuilding, batiments3d, bdtopoBuildings, type GeocodedPlace, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, type IgnPreset, } from './geoplateforme.ts';
35
+ export { BATIMENTS_3D_URL, type BdTopoBuilding, batiments3d, bdtopoBuildings, type GeocodedPlace, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, type IgnPreset, lambert93Grid, } from './geoplateforme.ts';
36
+ export { type Grid, windAt, windFields } from './grids.ts';
30
37
  export type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './layers/extrusions.ts';
31
38
  export { ExtrusionLayer } from './layers/extrusions.ts';
32
39
  export type { CircleOptions, CircleStyle, Feature, FeatureCollection, FeatureData, FeatureLayerStyle, FillOptions, FillStyle, Geometry, LineOptions, LineStyle, Placement, Position, Properties, Ramp, Size, Stops, Styled, } from './layers/features.ts';
33
40
  export { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from './layers/features.ts';
41
+ export type { FlowField, FlowOptions, FlowStyle, TimedField } from './layers/flow.ts';
42
+ export { FlowLayer, flowFieldFromImage, flowFieldsFromImage } from './layers/flow.ts';
34
43
  export type { TextPart } from './layers/glyphs.ts';
35
44
  export { DEFAULT_FONT, GLYPHS_URL } from './layers/glyphs.ts';
36
45
  export type { ImageOptions, Pixels, SpriteIcon } from './layers/icons.ts';
package/dist/index.js CHANGED
@@ -22,9 +22,11 @@ export { parseGpx } from "./data/gpx.js";
22
22
  export { parseKml } from "./data/kml.js";
23
23
  export { parseTopoJson } from "./data/topojson.js";
24
24
  export { setRequestHeaders } from "./engine/requests.js";
25
- export { BATIMENTS_3D_URL, batiments3d, bdtopoBuildings, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, } from "./geoplateforme.js";
25
+ export { BATIMENTS_3D_URL, batiments3d, bdtopoBuildings, geoplateformeGeocode, geoplateformeWfs, geoplateformeWms, geoplateformeWmts, IGN_ATTRIBUTION, IGN_PRESETS, lambert93Grid, } from "./geoplateforme.js";
26
+ export { windAt, windFields } from "./grids.js";
26
27
  export { ExtrusionLayer } from "./layers/extrusions.js";
27
28
  export { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from "./layers/features.js";
29
+ export { FlowLayer, flowFieldFromImage, flowFieldsFromImage } from "./layers/flow.js";
28
30
  export { DEFAULT_FONT, GLYPHS_URL } from "./layers/glyphs.js";
29
31
  export { CustomLayer, GroundLayer, Layer, ModelLayer, NetworkLayer, RasterLayer, Tiles3dLayer, } from "./layers/layers.js";
30
32
  export { Panoramas } from "./layers/panoramas.js";