diff --git a/lib/www/client/source/src/lib/deck.gl/DougalBinaryLoader.js b/lib/www/client/source/src/lib/deck.gl/DougalBinaryLoader.js new file mode 100644 index 0000000..5fe08cc --- /dev/null +++ b/lib/www/client/source/src/lib/deck.gl/DougalBinaryLoader.js @@ -0,0 +1,146 @@ +// src/lib/deck.gl/DougalBinaryLoader.js +import { LoaderObject } from '@loaders.gl/core'; +import { DougalBinaryBundle } from '@dougal/binary'; + +async function cachedFetch(url, init, opts = {}) { + let res; // The response + let cache; // Potentially, a Cache API cache name + let isCached; + + if (opts?.cache === true) { + opts.cache = { name: "dougal" }; + } else if (typeof opts?.cache === "string") { + opts.cache = { name: opts.cache }; + } else if (opts?.cache) { + if (!(opts.cache instanceof Object)) { + opts.cache = { name: "dougal" } + } else if (!(opts.cache.name)) { + opts.cache.name = "dougal"; + } + } + + if (opts?.cache) { + cache = await caches.open(opts.cache.name); + res = await cache.match(url); + isCached = !!res; + } + + if (!res) { + res = await fetch(url, init); + } + + if (cache && !isCached) { + cache.put(url, res.clone()); + } + + return res; +} + +const DougalBinaryLoader = { + name: 'DougalBinaryBundle Loader', + extensions: ['dbb'], + mimeTypes: ['application/vnd.aaltronav.dougal+octet-stream'], + parse: async (input, options) => { + let arrayBuffer; + if (typeof input === 'string') { + // Input is URL, fetch with caching + const response = await cachedFetch(input, options?.fetch, options); + if (!response.ok) { + throw new Error(`Failed to fetch: ${response.statusText}`); + } + arrayBuffer = await response.arrayBuffer(); + } else if (input instanceof ArrayBuffer) { + arrayBuffer = input; + } else { + throw new Error('Invalid input: Expected URL string or ArrayBuffer'); + } + + const bundle = DougalBinaryBundle.clone(arrayBuffer); + + // Calculate total points + const totalCount = bundle.chunks().reduce((acc, chunk) => acc + chunk.jCount, 0); + + // Prepare positions (Float32Array: [lon1, lat1, lon2, lat2, ...]) + const positions = new Float32Array(totalCount * 2); + + // Extract udv (assume constant across chunks) + const udv = bundle.chunks()[0].udv; + + // Prepare values as an array of TypedArrays + const ΔelemCount = bundle.chunks()[0].ΔelemCount; + const elemCount = bundle.chunks()[0].elemCount; + const values = new Array(ΔelemCount + elemCount + 2); + + // Initialize values arrays with correct types + if (udv == 0) { + for (let k = 0; k < values.length; k++) { + values[k] = new (k === 0 ? Uint16Array : k === 1 ? Uint32Array : Uint8Array)(totalCount); + } + } else if (udv == 1) { + for (let k = 0; k < values.length; k++) { + values[k] = new (k === 0 ? Uint16Array : k === 1 ? Uint32Array : k === 2 ? Uint8Array : Uint16Array)(totalCount); + } + } else if (udv == 2) { + for (let k = 0; k < values.length; k++) { + values[k] = new (k === 0 ? Uint16Array : k === 1 ? Uint32Array : k === 2 ? BigUint64Array : Float32Array)(totalCount); + } + } else { + throw new Error(`Invalid udv: Expected 0, 1, or 2; found ${udv}`); + } + + let offset = 0; + for (const chunk of bundle.chunks()) { + const λarray = chunk.elem(0); + const φarray = chunk.elem(1); + for (let i = 0; i < λarray.length; i++) { + positions[offset * 2 + i * 2] = λarray[i]; + positions[offset * 2 + i * 2 + 1] = φarray[i]; + } + + values[0].set(new Uint16Array(chunk.jCount).fill(chunk.i), offset); + values[1].set(Uint32Array.from({ length: chunk.jCount }, (_, i) => chunk.j0 + i * chunk.Δj), offset); + + for (let j = 0; j < ΔelemCount; j++) { + values[2 + j].set(chunk.Δelem(j), offset); + } + for (let j = 2; j < elemCount; j++) { + values[2 + ΔelemCount + j - 2].set(chunk.elem(j), offset); + } + + offset += chunk.jCount; + } + + console.log(`Parsed ${totalCount} points, ${values.length} value arrays`); + + const attributes = { + getPosition: { + value: positions, + type: 'float32', + size: 2 + }, + udv + }; + + values.forEach((valArray, k) => { + let value = valArray; + if (valArray instanceof BigUint64Array) { + value = Float64Array.from(valArray, v => Number(v)); + } + attributes[`value${k}`] = { + value, + type: value instanceof Float64Array ? 'float64' : + value instanceof Uint16Array ? 'uint16' : + value instanceof Uint32Array ? 'uint32' : 'float32', + size: 1 + }; + }); + + return { + length: totalCount, + attributes + }; + }, + options: {} // Optional: Add custom options if needed +}; + +export default DougalBinaryLoader;