"use strict";
/**
 * @module resample
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.resampleInterleaved = exports.resampleBilinearInterleaved = exports.resampleNearestInterleaved = exports.resample = exports.resampleBilinear = exports.resampleNearest = void 0;
function copyNewSize(array, width, height, samplesPerPixel = 1) {
    return new (Object.getPrototypeOf(array).constructor)(width * height * samplesPerPixel);
}
/**
 * Resample the input arrays using nearest neighbor value selection.
 * @param {TypedArray[]} valueArrays The input arrays to resample
 * @param {number} inWidth The width of the input rasters
 * @param {number} inHeight The height of the input rasters
 * @param {number} outWidth The desired width of the output rasters
 * @param {number} outHeight The desired height of the output rasters
 * @returns {TypedArray[]} The resampled rasters
 */
function resampleNearest(valueArrays, inWidth, inHeight, outWidth, outHeight) {
    const relX = inWidth / outWidth;
    const relY = inHeight / outHeight;
    return valueArrays.map((array) => {
        const newArray = copyNewSize(array, outWidth, outHeight);
        for (let y = 0; y < outHeight; ++y) {
            const cy = Math.min(Math.round(relY * y), inHeight - 1);
            for (let x = 0; x < outWidth; ++x) {
                const cx = Math.min(Math.round(relX * x), inWidth - 1);
                const value = array[(cy * inWidth) + cx];
                newArray[(y * outWidth) + x] = value;
            }
        }
        return newArray;
    });
}
exports.resampleNearest = resampleNearest;
// simple linear interpolation, code from:
// https://en.wikipedia.org/wiki/Linear_interpolation#Programming_language_support
function lerp(v0, v1, t) {
    return ((1 - t) * v0) + (t * v1);
}
/**
 * Resample the input arrays using bilinear interpolation.
 * @param {TypedArray[]} valueArrays The input arrays to resample
 * @param {number} inWidth The width of the input rasters
 * @param {number} inHeight The height of the input rasters
 * @param {number} outWidth The desired width of the output rasters
 * @param {number} outHeight The desired height of the output rasters
 * @returns {TypedArray[]} The resampled rasters
 */
function resampleBilinear(valueArrays, inWidth, inHeight, outWidth, outHeight) {
    const relX = inWidth / outWidth;
    const relY = inHeight / outHeight;
    return valueArrays.map((array) => {
        const newArray = copyNewSize(array, outWidth, outHeight);
        for (let y = 0; y < outHeight; ++y) {
            const rawY = relY * y;
            const yl = Math.floor(rawY);
            const yh = Math.min(Math.ceil(rawY), (inHeight - 1));
            for (let x = 0; x < outWidth; ++x) {
                const rawX = relX * x;
                const tx = rawX % 1;
                const xl = Math.floor(rawX);
                const xh = Math.min(Math.ceil(rawX), (inWidth - 1));
                const ll = array[(yl * inWidth) + xl];
                const hl = array[(yl * inWidth) + xh];
                const lh = array[(yh * inWidth) + xl];
                const hh = array[(yh * inWidth) + xh];
                const value = lerp(lerp(ll, hl, tx), lerp(lh, hh, tx), rawY % 1);
                newArray[(y * outWidth) + x] = value;
            }
        }
        return newArray;
    });
}
exports.resampleBilinear = resampleBilinear;
/**
 * Resample the input arrays using the selected resampling method.
 * @param {TypedArray[]} valueArrays The input arrays to resample
 * @param {number} inWidth The width of the input rasters
 * @param {number} inHeight The height of the input rasters
 * @param {number} outWidth The desired width of the output rasters
 * @param {number} outHeight The desired height of the output rasters
 * @param {string} [method = 'nearest'] The desired resampling method
 * @returns {TypedArray[]} The resampled rasters
 */
function resample(valueArrays, inWidth, inHeight, outWidth, outHeight, method = 'nearest') {
    switch (method.toLowerCase()) {
        case 'nearest':
            return resampleNearest(valueArrays, inWidth, inHeight, outWidth, outHeight);
        case 'bilinear':
        case 'linear':
            return resampleBilinear(valueArrays, inWidth, inHeight, outWidth, outHeight);
        default:
            throw new Error(`Unsupported resampling method: '${method}'`);
    }
}
exports.resample = resample;
/**
 * Resample the pixel interleaved input array using nearest neighbor value selection.
 * @param {TypedArray} valueArrays The input arrays to resample
 * @param {number} inWidth The width of the input rasters
 * @param {number} inHeight The height of the input rasters
 * @param {number} outWidth The desired width of the output rasters
 * @param {number} outHeight The desired height of the output rasters
 * @param {number} samples The number of samples per pixel for pixel
 *                         interleaved data
 * @returns {TypedArray} The resampled raster
 */
function resampleNearestInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples) {
    const relX = inWidth / outWidth;
    const relY = inHeight / outHeight;
    const newArray = copyNewSize(valueArray, outWidth, outHeight, samples);
    for (let y = 0; y < outHeight; ++y) {
        const cy = Math.min(Math.round(relY * y), inHeight - 1);
        for (let x = 0; x < outWidth; ++x) {
            const cx = Math.min(Math.round(relX * x), inWidth - 1);
            for (let i = 0; i < samples; ++i) {
                const value = valueArray[(cy * inWidth * samples) + (cx * samples) + i];
                newArray[(y * outWidth * samples) + (x * samples) + i] = value;
            }
        }
    }
    return newArray;
}
exports.resampleNearestInterleaved = resampleNearestInterleaved;
/**
 * Resample the pixel interleaved input array using bilinear interpolation.
 * @param {TypedArray} valueArrays The input arrays to resample
 * @param {number} inWidth The width of the input rasters
 * @param {number} inHeight The height of the input rasters
 * @param {number} outWidth The desired width of the output rasters
 * @param {number} outHeight The desired height of the output rasters
 * @param {number} samples The number of samples per pixel for pixel
 *                         interleaved data
 * @returns {TypedArray} The resampled raster
 */
function resampleBilinearInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples) {
    const relX = inWidth / outWidth;
    const relY = inHeight / outHeight;
    const newArray = copyNewSize(valueArray, outWidth, outHeight, samples);
    for (let y = 0; y < outHeight; ++y) {
        const rawY = relY * y;
        const yl = Math.floor(rawY);
        const yh = Math.min(Math.ceil(rawY), (inHeight - 1));
        for (let x = 0; x < outWidth; ++x) {
            const rawX = relX * x;
            const tx = rawX % 1;
            const xl = Math.floor(rawX);
            const xh = Math.min(Math.ceil(rawX), (inWidth - 1));
            for (let i = 0; i < samples; ++i) {
                const ll = valueArray[(yl * inWidth * samples) + (xl * samples) + i];
                const hl = valueArray[(yl * inWidth * samples) + (xh * samples) + i];
                const lh = valueArray[(yh * inWidth * samples) + (xl * samples) + i];
                const hh = valueArray[(yh * inWidth * samples) + (xh * samples) + i];
                const value = lerp(lerp(ll, hl, tx), lerp(lh, hh, tx), rawY % 1);
                newArray[(y * outWidth * samples) + (x * samples) + i] = value;
            }
        }
    }
    return newArray;
}
exports.resampleBilinearInterleaved = resampleBilinearInterleaved;
/**
 * Resample the pixel interleaved input array using the selected resampling method.
 * @param {TypedArray} valueArray The input array to resample
 * @param {number} inWidth The width of the input rasters
 * @param {number} inHeight The height of the input rasters
 * @param {number} outWidth The desired width of the output rasters
 * @param {number} outHeight The desired height of the output rasters
 * @param {number} samples The number of samples per pixel for pixel
 *                                 interleaved data
 * @param {string} [method = 'nearest'] The desired resampling method
 * @returns {TypedArray} The resampled rasters
 */
function resampleInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples, method = 'nearest') {
    switch (method.toLowerCase()) {
        case 'nearest':
            return resampleNearestInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples);
        case 'bilinear':
        case 'linear':
            return resampleBilinearInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples);
        default:
            throw new Error(`Unsupported resampling method: '${method}'`);
    }
}
exports.resampleInterleaved = resampleInterleaved;
//# sourceMappingURL=resample.js.map