Add DougalBinaryLoader Deck.gl loader

This commit is contained in:
D. Berge
2025-08-03 11:39:03 +02:00
parent c376896ea6
commit d16fb41f24

View File

@@ -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;