// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
const IDENTITY_MATRIX = [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1],
];
function matrixFromProto(matrix) {
    if (!matrix?.arrays || matrix.arrays.length !== 3) {
        return IDENTITY_MATRIX;
    }
    const rows = matrix.arrays.map((row) => row?.values ?? []);
    if (rows.some((row) => row.length !== 3)) {
        return IDENTITY_MATRIX;
    }
    return rows.map((row) => [row[0] ?? 0, row[1] ?? 0, row[2] ?? 0]);
}
function matrixEquals(a, b) {
    for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
            if (a[i][j] !== b[i][j]) {
                return false;
            }
        }
    }
    return true;
}
function matmul(a, b) {
    return [
        [
            a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0],
            a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1],
            a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2],
        ],
        [
            a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0],
            a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1],
            a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2],
        ],
        [
            a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0],
            a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1],
            a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2],
        ],
    ];
}
function matvecmul(m, vec) {
    const x = m[0][0] * vec.x + m[0][1] * vec.y + m[0][2];
    const y = m[1][0] * vec.x + m[1][1] * vec.y + m[1][2];
    const z = m[2][0] * vec.x + m[2][1] * vec.y + m[2][2];
    return { x: x / z, y: y / z };
}
function getMatrixInverse(matrix) {
    const det = matrix[0][0] * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1]) -
        matrix[0][1] * (matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0]) +
        matrix[0][2] * (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]);
    if (det === 0) {
        return IDENTITY_MATRIX;
    }
    const adj = [
        [
            matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1],
            -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1]),
            matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1],
        ],
        [
            -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0]),
            matrix[0][0] * matrix[2][2] - matrix[0][2] * matrix[2][0],
            -(matrix[0][0] * matrix[1][2] - matrix[0][2] * matrix[1][0]),
        ],
        [
            matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0],
            -(matrix[0][0] * matrix[2][1] - matrix[0][1] * matrix[2][0]),
            matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0],
        ],
    ];
    const invDet = 1 / det;
    return adj.map((row) => row.map((value) => value * invDet));
}
function buildTransformContext(transform) {
    if (!transform) {
        return undefined;
    }
    const width = transform.width ?? 0;
    const height = transform.height ?? 0;
    if (width <= 0 || height <= 0) {
        return undefined;
    }
    const matrix = matrixFromProto(transform.transformationMatrix);
    const sourceIntrinsicMatrix = matrixFromProto(transform.sourceIntrinsicMatrix);
    return {
        width,
        height,
        matrix,
        matrixInv: getMatrixInverse(matrix),
        sourceIntrinsicMatrix,
        sourceIntrinsicMatrixInv: getMatrixInverse(sourceIntrinsicMatrix),
    };
}
function interSourceFrameTransform(point, from, to) {
    if (matrixEquals(from.sourceIntrinsicMatrix, to.sourceIntrinsicMatrix)) {
        return point;
    }
    const transformMat = matmul(to.sourceIntrinsicMatrix, from.sourceIntrinsicMatrixInv);
    return matvecmul(transformMat, point);
}
function remapPointNormalized(from, to, point) {
    const denormalized = { x: point.x * from.width, y: point.y * from.height };
    const sourcePoint = matvecmul(from.matrixInv, denormalized);
    const sourcePointTo = interSourceFrameTransform(sourcePoint, from, to);
    const transformed = matvecmul(to.matrix, sourcePointTo);
    return { x: transformed.x / to.width, y: transformed.y / to.height };
}
function scaleValue(value, from, to) {
    const scaleX = to.width / from.width;
    const scaleY = to.height / from.height;
    return value * ((scaleX + scaleY) / 2);
}
export function getDepthaiTransformation(messageEvent) {
    if (!messageEvent || typeof messageEvent !== "object") {
        return undefined;
    }
    const candidate = messageEvent;
    return (candidate.depthaiTransformation ??
        candidate._depthai?.transformation ??
        candidate.message?.depthaiTransformation ??
        candidate.message?._depthai?.transformation);
}
export function remapDepthaiAnnotations(annotations, fromTransform, toTransform) {
    const fromCtx = buildTransformContext(fromTransform);
    const toCtx = buildTransformContext(toTransform);
    if (!fromCtx || !toCtx) {
        return annotations;
    }
    return annotations.map((annotation) => {
        switch (annotation.type) {
            case "points": {
                const points = annotation.points.map((point) => remapPointNormalized(fromCtx, toCtx, point));
                const thickness = scaleValue(annotation.thickness, fromCtx, toCtx);
                return { ...annotation, points, thickness };
            }
            case "text": {
                const position = remapPointNormalized(fromCtx, toCtx, annotation.position);
                const fontSize = scaleValue(annotation.fontSize, fromCtx, toCtx);
                const padding = scaleValue(annotation.padding, fromCtx, toCtx);
                return { ...annotation, position, fontSize, padding };
            }
            case "circle": {
                const position = remapPointNormalized(fromCtx, toCtx, annotation.position);
                const xPt = remapPointNormalized(fromCtx, toCtx, {
                    x: annotation.position.x + annotation.radius,
                    y: annotation.position.y,
                });
                const yPt = remapPointNormalized(fromCtx, toCtx, {
                    x: annotation.position.x,
                    y: annotation.position.y + annotation.radius,
                });
                const radiusX = Math.hypot(xPt.x - position.x, xPt.y - position.y);
                const radiusY = Math.hypot(yPt.x - position.x, yPt.y - position.y);
                const radius = (radiusX + radiusY) / 2;
                const thickness = scaleValue(annotation.thickness, fromCtx, toCtx);
                return { ...annotation, position, radius, thickness };
            }
            default:
                return annotation;
        }
    });
}
//# sourceMappingURL=depthaiTransform.js.map