const scratch_aabb = new Float32Array(4);


/**
 * NOTE: tends to overestimate the area
 * @param {number[]} aabb
 * @param {number[]} matrix
 * @return {number}
 */
export function aabb3_estimate_projected_area2(aabb, matrix) {
    // extract translation from matrix
    scratch_aabb[0] = scratch_aabb[2] = matrix[12];
    scratch_aabb[1] = scratch_aabb[3] = matrix[13];

    // apply 3x3 matrix transform
    for (let i = 0; i < 2; i++) {
        for (let j = 0; j < 3; j++) {

            const m_a = i  + j* 4;
            const m_v = matrix[m_a];

            const a = m_v * aabb[j];
            const b = m_v * aabb[j + 3];

            if (a < b) {
                scratch_aabb[i] += a;
                scratch_aabb[i + 2] += b;
            } else {
                scratch_aabb[i] += b;
                scratch_aabb[i + 2] += a;
            }
        }
    }


    const x1 = scratch_aabb[2];
    const x0 = scratch_aabb[0];

    const dx = x1 - x0;

    const y1 = scratch_aabb[3];
    const y0 = scratch_aabb[1];

    const dy = y1 - y0;
    const a = dx * dy;

    const cx = (aabb[0] + aabb[3]) * 0.5;
    const cy = (aabb[1] + aabb[4]) * 0.5;
    const cz = (aabb[2] + aabb[5]) * 0.5;

    /* compute W projection value, using conservative estimate
       @see https://twitter.com/SebAaltonen/status/1332332808979832832
       @see https://gist.github.com/slembcke/b2b2af4dede1d5702a635dc2d0e45d54
    */
    const w = matrix[3] * cx + matrix[7] * cy + matrix[11] * cz + matrix[15];
    const d = 0.5 / Math.abs(w);

    return a * d * d;
}
