// 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/
import { PointsAnnotationType } from "@foxglove/schemas";
import { estimateObjectSize } from "@foxglove/studio-base/players/messageMemoryEstimation.js";
import { DEFAULT_BACKGROUND_COLOR, DEBUG_COLOR, DEFAULT_TEXT_COLOR, DETECTION_STYLE, DEFAULT_STYLE, } from "./constants.js";
import { DEFAULT_HEIGHT, DEFAULT_WIDTH, getBorderThickness, getTextSize } from "./utils.js";
import { parseMessage } from "../../utils.js";
function rotatePoint(point, centerX, centerY, angleDegrees) {
    const angleRad = (angleDegrees * Math.PI) / 180;
    const xTranslated = point.x - centerX;
    const yTranslated = point.y - centerY;
    const xRotated = xTranslated * Math.cos(angleRad) - yTranslated * Math.sin(angleRad);
    const yRotated = xTranslated * Math.sin(angleRad) + yTranslated * Math.cos(angleRad);
    return {
        x: xRotated + centerX,
        y: yRotated + centerY,
    };
}
function getDetectionGeometry(detection, highlightSizeX, highlightSizeY) {
    const rotatedBoundingBox = detection.boundingBox;
    if (rotatedBoundingBox?.center && rotatedBoundingBox.size) {
        const { center, size, angle } = rotatedBoundingBox;
        const halfWidth = size.width / 2;
        const halfHeight = size.height / 2;
        const topLeft = rotatePoint({ x: center.x - halfWidth, y: center.y - halfHeight }, center.x, center.y, angle);
        const bottomLeft = rotatePoint({ x: center.x - halfWidth, y: center.y + halfHeight }, center.x, center.y, angle);
        const bottomRight = rotatePoint({ x: center.x + halfWidth, y: center.y + halfHeight }, center.x, center.y, angle);
        const topRight = rotatePoint({ x: center.x + halfWidth, y: center.y - halfHeight }, center.x, center.y, angle);
        const outline = [
            topLeft,
            bottomLeft,
            bottomRight,
            topRight,
        ];
        const highlightTopWidth = Math.min(highlightSizeX, size.width);
        const highlightSideHeight = Math.min(highlightSizeY, size.height);
        const highlightSegments = [
            [
                topLeft,
                rotatePoint({ x: center.x - halfWidth + highlightTopWidth, y: center.y - halfHeight }, center.x, center.y, angle),
            ],
            [
                topLeft,
                rotatePoint({ x: center.x - halfWidth, y: center.y - halfHeight + highlightSideHeight }, center.x, center.y, angle),
            ],
            [
                topRight,
                rotatePoint({ x: center.x + halfWidth - highlightTopWidth, y: center.y - halfHeight }, center.x, center.y, angle),
            ],
            [
                topRight,
                rotatePoint({ x: center.x + halfWidth, y: center.y - halfHeight + highlightSideHeight }, center.x, center.y, angle),
            ],
            [
                bottomRight,
                rotatePoint({ x: center.x + halfWidth - highlightTopWidth, y: center.y + halfHeight }, center.x, center.y, angle),
            ],
            [
                bottomRight,
                rotatePoint({ x: center.x + halfWidth, y: center.y + halfHeight - highlightSideHeight }, center.x, center.y, angle),
            ],
            [
                bottomLeft,
                rotatePoint({ x: center.x - halfWidth + highlightTopWidth, y: center.y + halfHeight }, center.x, center.y, angle),
            ],
            [
                bottomLeft,
                rotatePoint({ x: center.x - halfWidth, y: center.y + halfHeight - highlightSideHeight }, center.x, center.y, angle),
            ],
        ];
        const minX = Math.min(...outline.map((point) => point.x));
        const minY = Math.min(...outline.map((point) => point.y));
        return {
            outline,
            highlightSegments,
            labelPosition: { x: minX + highlightSizeX / 2, y: minY + highlightSizeY },
        };
    }
    const outline = [
        { x: detection.xmin, y: detection.ymin },
        { x: detection.xmin, y: detection.ymax },
        { x: detection.xmax, y: detection.ymax },
        { x: detection.xmax, y: detection.ymin },
    ];
    return {
        outline,
        highlightSegments: [
            [
                { x: detection.xmin, y: detection.ymin },
                { x: detection.xmin + highlightSizeX, y: detection.ymin },
            ],
            [
                { x: detection.xmin, y: detection.ymin },
                { x: detection.xmin, y: detection.ymin + highlightSizeY },
            ],
            [
                { x: detection.xmax, y: detection.ymin },
                { x: detection.xmax - highlightSizeX, y: detection.ymin },
            ],
            [
                { x: detection.xmax, y: detection.ymin },
                { x: detection.xmax, y: detection.ymin + highlightSizeY },
            ],
            [
                { x: detection.xmax, y: detection.ymax },
                { x: detection.xmax - highlightSizeX, y: detection.ymax },
            ],
            [
                { x: detection.xmax, y: detection.ymax },
                { x: detection.xmax, y: detection.ymax - highlightSizeY },
            ],
            [
                { x: detection.xmin, y: detection.ymax },
                { x: detection.xmin + highlightSizeX, y: detection.ymax },
            ],
            [
                { x: detection.xmin, y: detection.ymax },
                { x: detection.xmin, y: detection.ymax - highlightSizeY },
            ],
        ],
        labelPosition: { x: detection.xmin + highlightSizeX / 2, y: detection.ymin + highlightSizeY },
    };
}
export function deserializeImgDetections({ topic, message, callback, topicSizes, }) {
    const { receiveTime } = parseMessage(message);
    const foxgloveMessage = {
        points: [],
        texts: [],
        circles: [],
    };
    if (message.detections.length > 0) {
        for (const detection of message.detections) {
            const detectionWidth = detection.boundingBox?.size?.width ?? detection.xmax - detection.xmin;
            const detectionHeight = detection.boundingBox?.size?.height ?? detection.ymax - detection.ymin;
            const { width, height } = (message.transformation?.width && message.transformation.height
                ? { width: message.transformation.width, height: message.transformation.height }
                : topicSizes.values().next().value ?? { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT });
            const ratio = width / height;
            const highligtLength = 0.035;
            const highlightSizeX = Math.min(highligtLength, detectionWidth);
            const highlightSizeY = Math.min(highligtLength * ratio, detectionHeight);
            const geometry = getDetectionGeometry(detection, highlightSizeX, highlightSizeY);
            const style = DETECTION_STYLE[detection.label] ?? DEFAULT_STYLE;
            if (detection.labelName) {
                style.label = detection.labelName;
            }
            foxgloveMessage.points.push({
                timestamp: receiveTime,
                points: geometry.outline,
                type: PointsAnnotationType.LINE_LOOP,
                outline_colors: [],
                thickness: 0,
                outline_color: DEBUG_COLOR,
                fill_color: style.fill,
            });
            if (detection.keypoints) {
                const { keypoints, edges } = detection.keypoints;
                // Add keypoints as circles
                for (const keypoint of keypoints) {
                    if (keypoint.imageCoordinates) {
                        foxgloveMessage.circles.push({
                            timestamp: receiveTime,
                            position: {
                                x: keypoint.imageCoordinates.x,
                                y: keypoint.imageCoordinates.y,
                            },
                            diameter: 0.01,
                            thickness: 2,
                            fill_color: style.outline,
                            outline_color: style.outline,
                        });
                    }
                }
                // Add edges as line segments
                for (const edge of edges) {
                    const srcKeypoint = keypoints[edge.src];
                    const dstKeypoint = keypoints[edge.dst];
                    if (srcKeypoint?.imageCoordinates && dstKeypoint?.imageCoordinates) {
                        foxgloveMessage.points.push({
                            timestamp: receiveTime,
                            points: [
                                { x: srcKeypoint.imageCoordinates.x, y: srcKeypoint.imageCoordinates.y },
                                { x: dstKeypoint.imageCoordinates.x, y: dstKeypoint.imageCoordinates.y },
                            ],
                            type: PointsAnnotationType.LINE_LIST,
                            outline_colors: [],
                            thickness: 2,
                            outline_color: style.outline,
                            fill_color: DEBUG_COLOR,
                        });
                    }
                }
            }
            const baseHighlightConfig = {
                timestamp: receiveTime,
                type: PointsAnnotationType.LINE_LIST,
                outline_colors: [],
                thickness: getBorderThickness(width, height),
                outline_color: style.outline,
                fill_color: DEBUG_COLOR,
            };
            for (const segment of geometry.highlightSegments) {
                foxgloveMessage.points.push({
                    ...baseHighlightConfig,
                    points: segment,
                });
            }
            const label = `${style.label ?? `Unknown #${detection.label}`} ${Math.round(detection.confidence * 100)}%`;
            foxgloveMessage.texts.push({
                timestamp: receiveTime,
                position: geometry.labelPosition,
                text: label,
                font_size: getTextSize(width, height),
                text_color: DEFAULT_TEXT_COLOR,
                background_color: DEFAULT_BACKGROUND_COLOR,
            });
        }
    }
    callback({
        topic,
        receiveTime,
        message: foxgloveMessage,
        sizeInBytes: estimateObjectSize(foxgloveMessage),
        schemaName: "foxglove.ImageAnnotations",
        depthaiTransformation: message.transformation,
    });
}
//# sourceMappingURL=detection.js.map