utils/RasterWorker.tstypescript
import { BaseWorker } from "./BaseWorker";
import type { IWarpParams } from "../layer/geotiff/warp";
//@ts-ignore
import RasterWorkerImpl from "./RasterWorker.worker.js?worker&inline";
interface IRasterTask {
/** Task data with its type, the transferable buffers are moved to the worker. */
data: Record<string, any>;
transfer: Transferable[];
callback: (result: any) => void;
}
type MessageEventExt = MessageEvent & {
data: {
id: number;
result: any;
};
};
/**
* Raster pixels work out of the main thread: the terrain grid heights of the tile pixels, as createTileHeights
* makes them, and the GeoTIFF tile resampling, as warpRasters does.
*/
class RasterWorker extends BaseWorker<IRasterTask> {
constructor(numWorkers: number = 2) {
super(numWorkers, RasterWorkerImpl);
}
/**
* Returns the promise of the tile grid heights of the pixels, the pixels are moved to the worker.
*/
public heights(
pixels: Float32Array,
size: number,
gridSize: number,
levels: number,
noDataHeight: number
): Promise<Float32Array | null> {
return new Promise((resolve) =>
this.make({
data: { type: "heights", pixels, size, gridSize, levels, noDataHeight },
transfer: [pixels.buffer],
callback: resolve
})
);
}
/**
* Returns the promise of the resampled tile rasters, the window rasters and mask are moved to the worker.
*/
public warp(p: IWarpParams): Promise<Float32Array[] | null> {
let transfer: Transferable[] = p.rasters.map((r) => r.buffer);
if (p.maskRaster) {
transfer.push(p.maskRaster.buffer);
}
return new Promise((resolve) =>
this.make({
data: { type: "warp", ...p },
transfer: Array.from(new Set(transfer)),
callback: resolve
})
);
}
protected override _onMessage(e: MessageEventExt) {
let task = this._source.get(e.data.id)!;
this._source.delete(e.data.id);
task.callback(e.data.result);
}
public override make(task: IRasterTask) {
if (this._workerQueue.length) {
let w = this._workerQueue.pop()!;
this._source.set(this._sourceId, task);
w.postMessage({ id: this._sourceId, ...task.data }, task.transfer);
this._sourceId++;
} else {
this._pendingQueue.push(task);
}
}
}
let _rasterWorker: RasterWorker | null = null;
/**
* Returns the raster worker shared by the terrains and layers, null out of a browser.
*/
function getRasterWorker(): RasterWorker | null {
if (!_rasterWorker && typeof Worker !== "undefined") {
_rasterWorker = new RasterWorker(2);
}
return _rasterWorker;
}
export { RasterWorker, getRasterWorker };