mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 09:27:07 +00:00
Add DougalBinaryLoader Deck.gl loader
This commit is contained in:
146
lib/www/client/source/src/lib/deck.gl/DougalBinaryLoader.js
Normal file
146
lib/www/client/source/src/lib/deck.gl/DougalBinaryLoader.js
Normal 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;
|
||||||
Reference in New Issue
Block a user