"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Annotation
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.TextAnnotation = void 0;
const core_geometry_1 = require("@itwin/core-geometry");
const TextBlock_1 = require("./TextBlock");
/**
 * Represents a formatted block of text positioned in 2d or 3d space.
 * [TextAnnotation2d]($backend) and [TextAnnotation3d]($backend) elements store a single TextAnnotation from which their geometric representation is generated.
 * Other types of elements may store multiple TextAnnotations, positioned relative to one another.
 * The annotation's position and orientation relative to the host element's [Placement]($common) is determined as follows:
 * - First, a bounding box is computed enclosing the contents of the [[textBlock].
 * - Then, an "anchor point" is computed based on the bounding box and the [[anchor]] property. The anchor point can be at one of the four corners of the box, in the middle of one of its four
 * edges, or in the center of the box.
 * - The [[orientation]] is applied to rotate the box around the anchor point.
 * - Finally, the [[offset]] is added to the anchor point to apply translation.
 * @see [produceTextAnnotationGeometry]($backend) to decompose the annotation into a set of geometric primitives suitable for use with [[GeometryStreamBuilder.appendTextBlock]].
 * @beta
 */
class TextAnnotation {
    constructor(offset, angles, textBlock, anchor) {
        this.offset = offset;
        this.orientation = angles;
        this.textBlock = textBlock;
        this.anchor = anchor;
    }
    /** Creates a new TextAnnotation. */
    static create(args) {
        const offset = args?.offset ?? new core_geometry_1.Point3d();
        const angles = args?.orientation ?? new core_geometry_1.YawPitchRollAngles();
        const textBlock = args?.textBlock ?? TextBlock_1.TextBlock.createEmpty();
        const anchor = args?.anchor ?? { vertical: "top", horizontal: "left" };
        return new TextAnnotation(offset, angles, textBlock, anchor);
    }
    /**
     * Creates a new TextAnnotation instance from its JSON representation.
     */
    static fromJSON(props) {
        return TextAnnotation.create({
            offset: props?.offset ? core_geometry_1.Point3d.fromJSON(props.offset) : undefined,
            orientation: props?.orientation ? core_geometry_1.YawPitchRollAngles.fromJSON(props.orientation) : undefined,
            textBlock: props?.textBlock ? TextBlock_1.TextBlock.create(props.textBlock) : undefined,
            anchor: props?.anchor ? { ...props.anchor } : undefined,
        });
    }
    /**
     * Converts this annotation to its JSON representation.
     */
    toJSON() {
        const props = {};
        // Even if the text block is empty, we want to record its style name and overrides, e.g.,
        // so the user can pick up where they left off editing it next time.
        props.textBlock = this.textBlock.toJSON();
        if (!this.offset.isZero) {
            props.offset = this.offset.toJSON();
        }
        if (!this.orientation.isIdentity()) {
            props.orientation = this.orientation.toJSON();
        }
        if (this.anchor.vertical !== "top" || this.anchor.horizontal !== "left") {
            props.anchor = { ...this.anchor };
        }
        return props;
    }
    /** Compute the transform that positions and orients this annotation relative to its anchor point, based on the [[textBlock]]'s computed bounding box.
     * The anchor point is computed as specified by this annotation's [[anchor]] setting. For example, if the text block is anchored
     * at the bottom left, then the transform will be relative to the bottom-left corner of `textBlockExtents`.
     * The text block will be rotated around the fixed anchor point according to [[orientation]], then translated by [[offset]].
     * The anchor point will coincide with (0, 0, 0).
     * @param boundingBox A box fully containing the [[textBlock]].
     * @see [[computeAnchorPoint]] to compute the transform's anchor point.
     */
    computeTransform(boundingBox) {
        const anchorPt = this.computeAnchorPoint(boundingBox);
        const matrix = this.orientation.toMatrix3d();
        const rotation = core_geometry_1.Transform.createFixedPointAndMatrix(anchorPt, matrix);
        const translation = core_geometry_1.Transform.createTranslation(this.offset.minus(anchorPt));
        return translation.multiplyTransformTransform(rotation, rotation);
    }
    /** Compute the anchor point of this annotation as specified by [[anchor]].
     * @param boundingBox A box fully containing the [[textBlock]].
     * @see [[computeTransform]] to compute the transform relative to the anchor point.
     */
    computeAnchorPoint(boundingBox) {
        let x = boundingBox.low.x;
        let y = boundingBox.high.y;
        switch (this.anchor.horizontal) {
            case "center":
                x += boundingBox.xLength() / 2;
                break;
            case "right":
                x += boundingBox.xLength();
                break;
        }
        switch (this.anchor.vertical) {
            case "middle":
                y -= boundingBox.yLength() / 2;
                break;
            case "bottom":
                y -= boundingBox.yLength();
                break;
        }
        return new core_geometry_1.Point3d(x, y, 0);
    }
    /** Returns true if this annotation is logically equivalent to `other`. */
    equals(other) {
        return this.anchor.horizontal === other.anchor.horizontal && this.anchor.vertical === other.anchor.vertical
            && this.orientation.isAlmostEqual(other.orientation) && this.offset.isAlmostEqual(other.offset)
            && this.textBlock.equals(other.textBlock);
    }
}
exports.TextAnnotation = TextAnnotation;
//# sourceMappingURL=TextAnnotation.js.map