mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
Wind (NOAA GFS and ECMWF IFS: animated particles, colour field, a reading at map centre), observed weather (NOAA MRMS radar, GOES and NESDIS infrared clouds, lightning density) on one shared history timeline, NHC and CPHC cyclone advisories with tracks and cones, and a WEATHER panel in the right rail. On 3D Tiles the observed products render as raised shells with a sharper window around the view. Co-authored-by: Gustavo Beneduzi <[email protected]> Co-authored-by: Daniel Slay <[email protected]> Co-authored-by: Rehaan Delmotra <[email protected]> Co-authored-by: Cursor Agent <[email protected]>
52 lines
1.7 KiB
JavaScript
52 lines
1.7 KiB
JavaScript
/** Lazy shared ecCodes WASM instance, created only for an active wind request. */
|
|
let eccodesPromise = null;
|
|
function loadEccodes() {
|
|
eccodesPromise ??= import('@meri-imperiumi/eccodes-wasm')
|
|
.then((module) => module.createEccodes())
|
|
.catch((error) => {
|
|
eccodesPromise = null;
|
|
throw error;
|
|
});
|
|
return eccodesPromise;
|
|
}
|
|
|
|
/** Decode one bounded message in WASM memory without mounting the host filesystem. */
|
|
export async function decodeWindGribMessage(buffer, { eccodesModule } = {}) {
|
|
if (buffer.byteLength > 8 * 1024 * 1024)
|
|
throw new Error('Wind GRIB exceeds byte budget');
|
|
const eccodes = eccodesModule ?? (await loadEccodes());
|
|
// Everything after this await is synchronous. A shared virtual file is safe
|
|
// across U/V and model requests and its storage is released after each decode.
|
|
const file = '/gev-wind.grib2';
|
|
let handle = null;
|
|
try {
|
|
eccodes.writeFile(file, buffer);
|
|
handle = eccodes.openGrib(file);
|
|
const ni = handle.getLong('Ni');
|
|
const nj = handle.getLong('Nj');
|
|
if (
|
|
!Number.isInteger(ni) ||
|
|
!Number.isInteger(nj) ||
|
|
ni < 1 ||
|
|
nj < 1 ||
|
|
ni * nj > 2_000_000
|
|
)
|
|
throw new Error('Invalid wind GRIB geometry');
|
|
return {
|
|
ni,
|
|
nj,
|
|
lo1: handle.getDouble('longitudeOfFirstGridPointInDegrees'),
|
|
la1: handle.getDouble('latitudeOfFirstGridPointInDegrees'),
|
|
di: handle.getDouble('iDirectionIncrementInDegrees'),
|
|
dj: handle.getDouble('jDirectionIncrementInDegrees'),
|
|
values: handle.getDoubleArray('values'),
|
|
shortName: handle.getString('shortName'),
|
|
level: handle.getLong('level'),
|
|
units: handle.getString('units'),
|
|
};
|
|
} finally {
|
|
handle?.delete();
|
|
eccodes.writeFile(file, new Uint8Array(0));
|
|
}
|
|
}
|