"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformOcrBoundingBox = exports.transformFaceBoundingBox = exports.transformPoints = exports.createAffineMatrix = exports.getOutputDimensions = void 0;
const editing_dto_1 = require("../dtos/editing.dto");
const transformation_matrix_1 = require("transformation-matrix");
const getOutputDimensions = (edits, startingDimensions) => {
    let { width, height } = startingDimensions;
    const crop = edits.find((edit) => edit.action === editing_dto_1.AssetEditAction.Crop);
    if (crop) {
        width = crop.parameters.width;
        height = crop.parameters.height;
    }
    for (const edit of edits) {
        if (edit.action !== editing_dto_1.AssetEditAction.Rotate) {
            continue;
        }
        const angleDegrees = edit.parameters.angle;
        if (angleDegrees === 90 || angleDegrees === 270) {
            [width, height] = [height, width];
        }
    }
    return { width, height };
};
exports.getOutputDimensions = getOutputDimensions;
const createAffineMatrix = (edits, scalingParameters) => {
    let scalingMatrix = (0, transformation_matrix_1.identity)();
    if (scalingParameters) {
        const { pointSpace, targetSpace } = scalingParameters;
        const scaleX = targetSpace.width / pointSpace.width;
        scalingMatrix = (0, transformation_matrix_1.scale)(scaleX);
    }
    return (0, transformation_matrix_1.compose)(scalingMatrix, ...edits.map((edit) => {
        switch (edit.action) {
            case 'rotate': {
                const angleInRadians = (-edit.parameters.angle * Math.PI) / 180;
                return (0, transformation_matrix_1.rotate)(angleInRadians);
            }
            case 'mirror': {
                return edit.parameters.axis === 'horizontal' ? (0, transformation_matrix_1.flipY)() : (0, transformation_matrix_1.flipX)();
            }
            default: {
                return (0, transformation_matrix_1.identity)();
            }
        }
    }));
};
exports.createAffineMatrix = createAffineMatrix;
const transformPoints = (points, edits, startingDimensions, { inverse = false } = {}) => {
    let currentWidth = startingDimensions.width;
    let currentHeight = startingDimensions.height;
    let transformedPoints = [...points];
    if (!inverse) {
        const crop = edits.find((edit) => edit.action === 'crop');
        if (crop) {
            const { x: cropX, y: cropY, width: cropWidth, height: cropHeight } = crop.parameters;
            transformedPoints = transformedPoints.map((p) => ({
                x: p.x - cropX,
                y: p.y - cropY,
            }));
            currentWidth = cropWidth;
            currentHeight = cropHeight;
        }
    }
    const editSequence = inverse ? edits.toReversed() : edits;
    for (const edit of editSequence) {
        let matrix = (0, transformation_matrix_1.identity)();
        if (edit.action === 'rotate') {
            const angleDegrees = edit.parameters.angle;
            const angleRadians = (angleDegrees * Math.PI) / 180;
            const newWidth = angleDegrees === 90 || angleDegrees === 270 ? currentHeight : currentWidth;
            const newHeight = angleDegrees === 90 || angleDegrees === 270 ? currentWidth : currentHeight;
            matrix = (0, transformation_matrix_1.compose)((0, transformation_matrix_1.translate)(newWidth / 2, newHeight / 2), (0, transformation_matrix_1.rotate)(inverse ? -angleRadians : angleRadians), (0, transformation_matrix_1.translate)(-currentWidth / 2, -currentHeight / 2));
            currentWidth = newWidth;
            currentHeight = newHeight;
        }
        else if (edit.action === 'mirror') {
            matrix = (0, transformation_matrix_1.compose)((0, transformation_matrix_1.translate)(currentWidth / 2, currentHeight / 2), edit.parameters.axis === 'horizontal' ? (0, transformation_matrix_1.flipY)() : (0, transformation_matrix_1.flipX)(), (0, transformation_matrix_1.translate)(-currentWidth / 2, -currentHeight / 2));
        }
        else {
            continue;
        }
        transformedPoints = transformedPoints.map((p) => (0, transformation_matrix_1.applyToPoint)(matrix, p));
    }
    if (inverse) {
        const crop = edits.find((edit) => edit.action === 'crop');
        if (crop) {
            const { x: cropX, y: cropY } = crop.parameters;
            transformedPoints = transformedPoints.map((p) => ({
                x: p.x + cropX,
                y: p.y + cropY,
            }));
        }
    }
    return {
        points: transformedPoints,
        currentWidth,
        currentHeight,
    };
};
exports.transformPoints = transformPoints;
const transformFaceBoundingBox = (box, edits, imageDimensions) => {
    if (edits.length === 0) {
        return box;
    }
    const scaleX = imageDimensions.width / box.imageWidth;
    const scaleY = imageDimensions.height / box.imageHeight;
    const points = [
        { x: box.boundingBoxX1 * scaleX, y: box.boundingBoxY1 * scaleY },
        { x: box.boundingBoxX2 * scaleX, y: box.boundingBoxY2 * scaleY },
    ];
    const { points: transformedPoints, currentWidth, currentHeight } = (0, exports.transformPoints)(points, edits, imageDimensions);
    const [p1, p2] = transformedPoints;
    return {
        boundingBoxX1: Math.trunc(Math.min(p1.x, p2.x)),
        boundingBoxY1: Math.trunc(Math.min(p1.y, p2.y)),
        boundingBoxX2: Math.trunc(Math.max(p1.x, p2.x)),
        boundingBoxY2: Math.trunc(Math.max(p1.y, p2.y)),
        imageWidth: currentWidth,
        imageHeight: currentHeight,
    };
};
exports.transformFaceBoundingBox = transformFaceBoundingBox;
const reorderQuadPointsForRotation = (points, rotationDegrees) => {
    const [p1, p2, p3, p4] = points;
    switch (rotationDegrees) {
        case 90: {
            return [p4, p1, p2, p3];
        }
        case 180: {
            return [p3, p4, p1, p2];
        }
        case 270: {
            return [p2, p3, p4, p1];
        }
        default: {
            return points;
        }
    }
};
const transformOcrBoundingBox = (box, edits, imageDimensions) => {
    if (edits.length === 0) {
        return box;
    }
    const points = [
        { x: box.x1 * imageDimensions.width, y: box.y1 * imageDimensions.height },
        { x: box.x2 * imageDimensions.width, y: box.y2 * imageDimensions.height },
        { x: box.x3 * imageDimensions.width, y: box.y3 * imageDimensions.height },
        { x: box.x4 * imageDimensions.width, y: box.y4 * imageDimensions.height },
    ];
    const { points: transformedPoints, currentWidth, currentHeight } = (0, exports.transformPoints)(points, edits, imageDimensions);
    const netRotation = edits.find((e) => e.action == editing_dto_1.AssetEditAction.Rotate)?.parameters.angle ?? 0 % 360;
    const reorderedPoints = reorderQuadPointsForRotation(transformedPoints, netRotation);
    const [p1, p2, p3, p4] = reorderedPoints;
    return {
        ...box,
        x1: p1.x / currentWidth,
        y1: p1.y / currentHeight,
        x2: p2.x / currentWidth,
        y2: p2.y / currentHeight,
        x3: p3.x / currentWidth,
        y3: p3.y / currentHeight,
        x4: p4.x / currentWidth,
        y4: p4.y / currentHeight,
    };
};
exports.transformOcrBoundingBox = transformOcrBoundingBox;
//# sourceMappingURL=transform.js.map