/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Views
 */
/** A rectangle in unsigned integer view coordinates with (0,0) corresponding to the top-left corner of the view.
 * Increasing **x** moves from left to right, and increasing **y** moves from top to bottom.
 * [[left]], [[top]], [[right]], and [[bottom]] are required to be non-negative integers; any negative inputs are treated as
 * zero and any non-integer inputs are rounded down to the nearest integer.
 * @public
 * @extensions
 */
export class ViewRect {
    _left;
    _top;
    _right;
    _bottom;
    _set(key, value) {
        this[key] = Math.max(0, Math.floor(value));
    }
    /** Construct a new ViewRect. */
    constructor(left = 0, top = 0, right = 0, bottom = 0) { this.init(left, top, right, bottom); }
    /** The leftmost side of this ViewRect. */
    get left() { return this._left; }
    set left(val) { this._set("_left", val); }
    /** The topmost side of this ViewRect. */
    get top() { return this._top; }
    set top(val) { this._set("_top", val); }
    /** The rightmost side of this ViewRect. */
    get right() { return this._right; }
    set right(val) { this._set("_right", val); }
    /** The bottommost side of this ViewRect. */
    get bottom() { return this._bottom; }
    set bottom(val) { this._set("_bottom", val); }
    /** True if this ViewRect has an area <= 0. */
    get isNull() { return this.right <= this.left || this.bottom <= this.top; }
    /** True if `!isNull` */
    get isValid() { return !this.isNull; }
    /** The width (right-left) of this ViewRect. */
    get width() { return this.right - this.left; }
    set width(width) { this.right = this.left + width; }
    /** The height (bottom-top) of this ViewRect. */
    get height() { return this.bottom - this.top; }
    set height(height) { this.bottom = this.top + height; }
    /** The aspect ratio (width/height) of this ViewRect. */
    get aspect() { return this.isNull ? 1.0 : this.width / this.height; }
    /** The area (width*height) of this ViewRect. */
    get area() { return this.isNull ? 0 : this.width * this.height; }
    /** Initialize this ViewRect from its left/top/right/bottom parameters. */
    init(left, top, right, bottom) {
        this.left = left;
        this.bottom = bottom, this.right = right;
        this.top = top;
    }
    /** Initialize this ViewRect from two points.
     * @param topLeft The top-left corner.
     * @param bottomRight The bottom-right corner.
     */
    initFromPoints(topLeft, bottomRight) { this.init(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); }
    /** Initialize this ViewRect from a range.
     * @param input The Range to use. `input.low` defines the top-left and `input.high` defines the bottom-right.
     */
    initFromRange(input) { this.initFromPoints(input.low, input.high); }
    /** Return true is this ViewRect is exactly equal to another ViewRect.
     * @param other The other ViewRect to compare
     */
    equals(other) { return this.left === other.left && this.right === other.right && this.bottom === other.bottom && this.top === other.top; }
    /** Initialize this ViewRect from another ViewRect. */
    setFrom(other) { this.init(other.left, other.top, other.right, other.bottom); }
    /** Duplicate this ViewRect.
     * @param result Optional ViewRect for result. If undefined, a new ViewRect is created.
     */
    clone(result) {
        if (undefined !== result) {
            result.setFrom(this);
            return result;
        }
        return new ViewRect(this.left, this.top, this.right, this.bottom);
    }
    extend(other) {
        if (this.left > other.left)
            this.left = other.left;
        if (this.top > other.top)
            this.top = other.top;
        if (this.right < other.right)
            this.right = other.right;
        if (this.bottom < other.bottom)
            this.bottom = other.bottom;
    }
    /** Inset this ViewRect by values in the x and y directions. Positive values make the ViewRect smaller, and negative values will make it larger.
     * @param deltaX The distance to inset the ViewRect in the x direction.
     * @param deltaY The distance to inset the ViewRect in the y direction.
     */
    inset(deltaX, deltaY) {
        deltaX = Math.floor(deltaX);
        deltaY = Math.floor(deltaY);
        if (this.width - 2 * deltaX <= 0 || this.height - 2 * deltaY <= 0) {
            this.init(0, 0, 0, 0);
            return;
        }
        this._left += deltaX;
        this._right -= deltaX;
        this._top += deltaY;
        this._bottom -= deltaY;
    }
    /** Inset this ViewRect by the same value in all directions.
     * @param offset The distance to inset this ViewRect. Positive values will make this ViewRect smaller and negative values will make it larger.
     * @note The inset operation can cause a previously valid ViewRect to become invalid.
     */
    insetUniform(offset) { this.inset(offset, offset); }
    /** Scale this ViewRect about its center by the supplied scale factors. */
    scaleAboutCenter(xScale, yScale) {
        const w = this.width;
        const h = this.height;
        const xDelta = (w - (w * xScale)) * 0.5;
        const yDelta = (h - (h * yScale)) * 0.5;
        this.inset(xDelta, yDelta);
    }
    /** Inset this ViewRect by a percentage of its current width.
     * @param percent The percentage of this ViewRect's width to inset in all directions.
     * @note The ViewRect will become smaller (or larger, if percent is negative) by `percent * width * 2` in each direction, since each side is moved by that distance.
     * @see [[inset]]
     */
    insetByPercent(percent) { this.insetUniform(this.width * percent); }
    /** Determine if this ViewRect is entirely contained within the bounds of another ViewRect. */
    isContained(other) { return this.left >= other.left && this.right <= other.right && this.bottom <= other.bottom && this.top >= other.top; }
    /** Return true if the supplied point is contained in this ViewRect.
     * @param point The point to test.
     * @note if the point is exactly on the left or top edges, this method returns true. If the point is exactly on the right or bottom edge, it returns false.
     */
    containsPoint(point) { return point.x >= this.left && point.x < this.right && point.y >= this.top && point.y < this.bottom; }
    /** Determine whether this ViewRect overlaps another. */
    overlaps(other) { return this.left <= other.right && this.top <= other.bottom && this.right >= other.left && this.bottom >= other.top; }
    /** Return a ViewRect that is the overlap (intersection) of this ViewRect and another ViewRect.
     * If the two ViewRects are equal, their value is the result. Otherwise, the result will always be smaller than either of them.
     */
    computeOverlap(other, out) {
        const maxOrgX = Math.max(this.left, other.left);
        const maxOrgY = Math.max(this.top, other.top);
        const minCrnX = Math.min(this.right, other.right);
        const minCrnY = Math.min(this.bottom, other.bottom);
        if (maxOrgX > minCrnX || maxOrgY > minCrnY)
            return undefined;
        const result = undefined !== out ? out : new ViewRect();
        result.left = maxOrgX;
        result.right = minCrnX;
        result.top = maxOrgY;
        result.bottom = minCrnY;
        return result;
    }
}
//# sourceMappingURL=ViewRect.js.map