Elevation grid from a surface
32-bit in partThe elevation at the center of every grid cell, row by row from the north.
x₀ = ⌊minX ÷ cell⌋·cell; y₀ = ⌈maxY ÷ cell⌉·cell; center = (x₀ + (c + 0.5)·cell, y₀ − (r + 0.5)·cell)
The elevation comes from the surface as a 64-bit number and is stored straight into a Float32Array, so the exported value keeps about 7 significant digits. Cell centers are index × cell from the origin, not running sums. Cells outside the surface take the no-data value.
export async function surfaceGrid(surface, { cell, toGrid = (x, y) => [x, y], fromGrid = (x, y) => [x, y], signal = null, progress = null, maxCells = 25e6 } = {}) {
if (!(cell > 0) || !Number.isFinite(cell)) throw new Error(t('gtw.cell.bad'));
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
for (const loop of surface.outline()) for (const p of loop) {
const [gx, gy] = toGrid(p.x, p.y);
minX = Math.min(minX, gx); maxX = Math.max(maxX, gx); minY = Math.min(minY, gy); maxY = Math.max(maxY, gy);
}
if (!Number.isFinite(minX)) throw new Error(t('gtw.no_outline'));
const x0 = Math.floor(minX / cell) * cell, y0 = Math.ceil(maxY / cell) * cell;
const width = Math.max(1, Math.ceil((maxX - x0) / cell - 1e-9)), height = Math.max(1, Math.ceil((y0 - minY) / cell - 1e-9));
if (width * height > maxCells) throw new Error(t('gtw.too_many', { w: width.toLocaleString('en-US'), h: height.toLocaleString('en-US'), cells: (width * height / 1e6).toFixed(1), max: String(maxCells / 1e6) }));
const values = new Float32Array(width * height);
for (let r = 0; r < height; r++) {
const gy = y0 - (r + 0.5) * cell;
for (let c = 0; c < width; c++) {
const [x, y] = fromGrid(x0 + (c + 0.5) * cell, gy);
const z = surface.elevationAt(x, y);
values[r * width + c] = z === null ? NODATA : z;
}
if ((r & 63) === 63) { aborted(signal); if (progress) { progress(r / height); await tick(); } }
}
return { width, height, gt: [x0, cell, 0, y0, 0, -cell], values };
}