Files
BrainWind/app/src/lib/bilinear-interp.ts
T

63 lines
1.8 KiB
TypeScript

/**
* Interpolação bilinear 2D conforme plano técnico (sec. 3.2).
*
* Dados quatro pontos Q₁₁(x₁,y₁), Q₁₂(x₁,y₂), Q₂₁(x₂,y₁), Q₂₂(x₂,y₂),
* estima f(x,y) por:
* f ≈ ((x₂-x)(y₂-y)·f₁₁ + (x-x₁)(y₂-y)·f₂₁ + (x₂-x)(y-y₁)·f₁₂ + (x-x₁)(y-y₁)·f₂₂) /
* ((x₂-x₁)(y₂-y₁))
*
* Aceita x fora do intervalo por extrapolação linear (clamp opcional).
*/
export type Grid2D = {
xs: readonly number[];
ys: readonly number[];
values: readonly (readonly number[])[];
};
function findBracket(xs: readonly number[], x: number): [number, number, boolean] {
const clamped = Math.max(xs[0], Math.min(x, xs[xs.length - 1]));
const extrapolated = clamped !== x;
if (xs.length === 1) return [0, 0, extrapolated];
if (clamped >= xs[xs.length - 1]) {
return [xs.length - 2, xs.length - 1, extrapolated];
}
for (let i = 0; i < xs.length - 1; i++) {
const a = xs[i];
const b = xs[i + 1];
if (clamped >= a && clamped <= b) {
return [i, i + 1, extrapolated];
}
}
return [0, xs.length - 1, extrapolated];
}
export function bilinearInterp(grid: Grid2D, x: number, y: number): number {
const { xs, ys, values } = grid;
const [ix0, ix1] = findBracket(xs, x);
const [iy0, iy1] = findBracket(ys, y);
const x1 = xs[ix0];
const x2 = xs[ix1];
const y1 = ys[iy0];
const y2 = ys[iy1];
const f11 = values[iy0][ix0];
const f21 = values[iy0][ix1];
const f12 = values[iy1][ix0];
const f22 = values[iy1][ix1];
const dx = x2 - x1;
const dy = y2 - y1;
if (dx === 0 || dy === 0) return f11;
const denom = dx * dy;
const num =
(x2 - x) * (y2 - y) * f11 +
(x - x1) * (y2 - y) * f21 +
(x2 - x) * (y - y1) * f12 +
(x - x1) * (y - y1) * f22;
return num / denom;
}