gis-tools-ts
Version:
A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.
92 lines • 3.67 kB
JavaScript
import { pointDistance as distance } from '../../geometry/s2/point';
import { averageInterpolation, defaultGetInterpolateCurrentValue } from '.';
import { lRGBToGamma, sRGBToLinear } from '../..';
/**
* # Lanczos Interpolation
*
* ## Description
* Perform interpolation using the Lanczos filter. This method uses a kernel-based approach
* to weigh contributions from nearby points, providing a balance between smoothing and sharpness.
*
* ## Usage
* ```ts
* import { lanczosInterpolation, PointIndexFast } from 'gis-tools-ts';
* import type { VectorPoint } from 'gis-tools-ts';
*
* // We have m-value data that we want to interpolate
* interface TempData { temp: number; }
*
* const pointIndex = new PointIndexFast<TempData>();
* // add lots of points
* pointIndex.insertLonLat(lon, lat, data);
* // ....
*
* // given a point we are interested in
* const point: VectorPoint = { x: 20, y: -40 };
* // get a collection of points relative to the point
* const data = await pointIndex.searchRadius(point.x, point.y, radius);
*
* // interpolate
* const interpolatedValue = lanczosInterpolation<TempData>(point, data, (p) => p.m.temp);
* ```
* @param point - Point to interpolate
* @param refData - Reference data points
* @param getValue - Function to extract the value from a reference point
* @param kernelRadius - Lanczos kernel radius (default is 2) Recommend to only use 2 or 3.
* @returns - The interpolated value
*/
export function lanczosInterpolation(point, refData, getValue = defaultGetInterpolateCurrentValue, kernelRadius = 2) {
if (refData.length === 0)
return 0;
let numerator = 0;
let denom = 0;
for (const refPoint of refData) {
const weight = lanczosKernel(distance(point, refPoint), kernelRadius);
const value = getValue(refPoint);
numerator += value * weight;
denom += weight;
}
// Avoid division by zero
if (denom === 0)
return 0;
return numerator / denom;
}
/**
* Helper function for {@link lanczosInterpolation} on RGB(A) data.
* Light in RGB data is logarithmically weighted, so we need to expand each component by n^2 to
* get the correct weight for each component.
* @param point - Point to interpolate
* @param refData - Reference data points
* @param kernelRadius - Lanczos kernel radius (default is 2) Recommend to only use 2 or 3.
* @returns - The interpolated RGBA data.
*/
export function rgbaLanczosInterpolation(point, refData, kernelRadius = 2) {
if (refData.length === 0)
return { r: 0, g: 0, b: 0, a: 255 };
const rData = lanczosInterpolation(point, refData, (p) => sRGBToLinear(p.m?.r ?? 0), kernelRadius);
const gData = lanczosInterpolation(point, refData, (p) => sRGBToLinear(p.m?.g ?? 0), kernelRadius);
const bData = lanczosInterpolation(point, refData, (p) => sRGBToLinear(p.m?.b ?? 0), kernelRadius);
const a = averageInterpolation(point, refData, (p) => p.m?.a ?? 255);
return {
r: lRGBToGamma(rData),
g: lRGBToGamma(gData),
b: lRGBToGamma(bData),
a,
};
}
/**
* Lanczos kernel function - returns the weight based on the distance from the target point
* https://en.wikipedia.org/wiki/Lanczos_resampling
* @param x - distance from the target point
* @param a - Lanczos kernel radius (default 2)
* @returns - weight based on the Lanczos kernel
*/
function lanczosKernel(x, a) {
if (x === 0)
return 1; // sinc(0) = 1
if (Math.abs(x) >= a)
return 0; // Outside the kernel radius
const piX = Math.PI * x;
return (Math.sin(piX) / piX) * (Math.sin(piX / a) / (piX / a));
}
//# sourceMappingURL=lanczos.js.map