import { Point } from './point';
import { Polyline } from './polyline';
import { GeomConstants } from './geomConstants';
export class Size {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }
    pad(padW) {
        this.width += padW * 2;
    }
}
export class Rectangle {
    constructor(t) {
        this.left_ = t.left;
        this.right_ = t.right;
        this.top_ = t.top;
        this.bottom = t.bottom;
    }
    static mkSizeCenter(size, center) {
        const w = size.width / 2;
        const h = size.height / 2;
        return new Rectangle({
            left: center.x - w,
            right: center.x + w,
            bottom: center.y - h,
            top: center.y + h,
        });
    }
    add_rect(rectangle) {
        return this.addRec(rectangle);
    }
    contains_point(point) {
        return this.contains(point);
    }
    contains_rect(rect) {
        return this.containsRect(rect);
    }
    intersection_rect(rectangle) {
        return this.intersection(rectangle);
    }
    intersects_rect(rectangle) {
        return this.intersects(rectangle);
    }
    unite(b) {
        return Rectangle.rectangleOfTwo(this, b);
    }
    contains_point_radius(p, radius) {
        return this.containsWithPadding(p, radius);
    }
    // returns true if r intersect this rectangle
    intersects(rectangle) {
        return this.intersectsOnX(rectangle) && this.intersectsOnY(rectangle);
    }
    // intersection (possibly empty) of rectangles
    intersection(rectangle) {
        if (!this.intersects(rectangle)) {
            const intersection = Rectangle.mkEmpty();
            intersection.setToEmpty();
            return intersection;
        }
        const l = Math.max(this.left, rectangle.left);
        const r = Math.min(this.right, rectangle.right);
        const b = Math.max(this.bottom, rectangle.bottom);
        const t = Math.min(this.top, rectangle.top);
        return new Rectangle({ left: l, bottom: b, right: r, top: t });
    }
    // the center of the bounding box
    get center() {
        return this.leftTop.add(this.rightBottom).mul(0.5);
    }
    set center(value) {
        const shift = value.sub(this.center);
        this.leftTop = this.leftTop.add(shift);
        this.rightBottom = this.rightBottom.add(shift);
    }
    intersectsOnY(r) {
        if (r.bottom_ > this.top_ + GeomConstants.distanceEpsilon)
            return false;
        if (r.top_ < this.bottom_ - GeomConstants.distanceEpsilon)
            return false;
        return true;
    }
    intersectsOnX(r) {
        if (r.left > this.right_ + GeomConstants.distanceEpsilon)
            return false;
        if (r.right < this.left_ - GeomConstants.distanceEpsilon)
            return false;
        return true;
    }
    // creates an empty rectangle
    static mkEmpty() {
        return new Rectangle({ left: 0, right: -1, bottom: 0, top: -1 });
    }
    get left() {
        return this.left_;
    }
    set left(value) {
        this.left_ = value;
    }
    get right() {
        return this.right_;
    }
    set right(value) {
        this.right_ = value;
    }
    get top() {
        return this.top_;
    }
    set top(value) {
        this.top_ = value;
    }
    get bottom() {
        return this.bottom_;
    }
    set bottom(value) {
        this.bottom_ = value;
        if (Math.abs(value - 327.2399380885514) < 0.00001) {
            console.log(this);
        }
    }
    get leftBottom() {
        return new Point(this.left_, this.bottom_);
    }
    set leftBottom(value) {
        this.left_ = value.x;
        this.bottom = value.y;
    }
    get rightTop() {
        return new Point(this.right_, this.top_);
    }
    set rightTop(value) {
        this.right_ = value.x;
        this.top_ = value.y;
    }
    get leftTop() {
        return new Point(this.left_, this.top_);
    }
    set leftTop(value) {
        this.left_ = value.x;
        this.top_ = value.y;
    }
    get rightBottom() {
        return new Point(this.right_, this.bottom_);
    }
    set rightBottom(value) {
        this.right_ = value.x;
        this.bottom = value.y;
    }
    // create a box of two points
    static mkPP(point0, point1) {
        const r = new Rectangle({
            left: point0.x,
            right: point0.x,
            top: point0.y,
            bottom: point0.y,
        });
        r.add(point1);
        return r;
    }
    // create rectangle from a point
    static rectangleOnPoint(p) {
        return new Rectangle({ left: p.x, right: p.x, top: p.y, bottom: p.y });
    }
    static rectangleFromLeftBottomAndSize(left, bottom, sizeF) {
        const right = left + sizeF.x;
        const top = bottom + sizeF.y;
        return new Rectangle({ left: left, right: right, top: top, bottom: bottom });
    }
    // create a box on points (x0,y0), (x1,y1)
    static getRectangleOnCoords(x0, y0, x1, y1) {
        const r = new Rectangle({ left: x0, bottom: y0, right: x0, top: y0 });
        r.add(new Point(x1, y1));
        return r;
    }
    // Create rectangle that is the bounding box of the given points
    static mkOnPoints(points) {
        const r = Rectangle.mkEmpty();
        for (const p of points) {
            r.add(p);
        }
        return r;
    }
    // Create rectangle that is the bounding box of the given Rectangles
    static rectangleOnRectangles(rectangles) {
        const r = Rectangle.mkEmpty();
        for (const p of rectangles) {
            r.addRecSelf(p);
        }
        return r;
    }
    // the width of the rectangle
    get width() {
        return this.right_ - this.left_;
    }
    set width(value) {
        const hw = value / 2.0;
        const cx = (this.left_ + this.right_) / 2.0;
        this.left_ = cx - hw;
        this.right_ = cx + hw;
    }
    // returns true if the rectangle has negative width
    isEmpty() {
        return this.width < 0;
    }
    // makes the rectangle empty
    setToEmpty() {
        this.left = 0;
        this.right = -1;
    }
    // height of the rectangle
    get height() {
        return this.top_ - this.bottom_;
    }
    set height(value) {
        const hw = value / 2.0;
        const cx = (this.top_ + this.bottom_) / 2.0;
        this.top_ = cx + hw;
        this.bottom = cx - hw;
    }
    // rectangle containing both a and b
    static rectangleOfTwo(a, b) {
        const r = new Rectangle({
            left: a.left_,
            right: a.right_,
            top: a.top_,
            bottom: a.bottom_,
        });
        r.addRecSelf(b);
        return r;
    }
    // contains with padding
    containsWithPadding(point, padding) {
        return (this.left_ - padding - GeomConstants.distanceEpsilon <= point.x &&
            point.x <= this.right_ + padding + GeomConstants.distanceEpsilon &&
            this.bottom_ - padding - GeomConstants.distanceEpsilon <= point.y &&
            point.y <= this.top_ + padding + GeomConstants.distanceEpsilon);
    }
    // Rectangle area
    get area() {
        return (this.right_ - this.left_) * (this.top_ - this.bottom_);
    }
    // adding a point to the rectangle
    add(point) {
        if (!this.isEmpty()) {
            if (this.left_ > point.x)
                this.left_ = point.x;
            if (this.top_ < point.y)
                this.top_ = point.y;
            if (this.right_ < point.x)
                this.right_ = point.x;
            if (this.bottom_ > point.y)
                this.bottom = point.y;
        }
        else {
            this.left_ = this.right_ = point.x;
            this.top_ = this.bottom = point.y;
        }
    }
    // extend the box to keep the point.
    // Assume here that the box is initialized correctly
    addWithCheck(point) {
        let wider;
        if ((wider = point.x < this.left_))
            this.left_ = point.x;
        else if ((wider = this.right_ < point.x))
            this.right_ = point.x;
        let higher;
        if ((higher = point.y > this.top_))
            this.top_ = point.y;
        else if ((higher = this.bottom_ > point.y))
            this.bottom = point.y;
        return wider || higher;
    }
    // adding rectangle
    addRecSelf(rectangle) {
        this.add(rectangle.leftTop);
        this.add(rectangle.rightBottom);
    }
    // adding rectangle
    addRec(rectangle) {
        const ret = this.clone();
        ret.add(rectangle.leftTop);
        ret.add(rectangle.rightBottom);
        return ret;
    }
    // Return copy of specified rectangle translated by the specified delta
    static translate(rectangle, delta) {
        const r = rectangle.clone();
        r.center = rectangle.center.add(delta);
        return r;
    }
    // returns true if the rectangle contains the point
    contains(point) {
        return this.containsWithPadding(point, 0);
    }
    // returns true if this rectangle compconstely contains the specified rectangle
    containsRect(rect) {
        return this.contains(rect.leftTop) && this.contains(rect.rightBottom);
    }
    // return the length of the diagonal
    get diagonal() {
        return Math.sqrt(this.width * this.width + this.height * this.height);
    }
    // pad the rectangle horizontally by the given padding
    padWidth(padding) {
        this.left -= padding;
        this.right += padding;
    }
    // pad the rectangle vertically by the given padding
    padHeight(padding) {
        this.top += padding;
        this.bottom -= padding;
    }
    // pad the rectangle by the given padding
    pad(padding) {
        if (padding < -this.width / 2)
            padding = -this.width / 2;
        if (padding < -this.height / 2)
            padding = -this.height / 2;
        this.padWidth(padding);
        this.padHeight(padding);
        return this;
    }
    // Pad the rectangle by the given amount on each side
    padEverywhere(margins) {
        this.left -= margins.left;
        this.right += margins.right;
        this.bottom -= margins.bottom;
        this.top += margins.top;
    }
    // Returns the intersection of two rectangles.
    static intersect(rect1, rect2) {
        if (rect1.intersects(rect2))
            return Rectangle.mkPP(new Point(Math.max(rect1.left, rect2.left), Math.max(rect1.bottom, rect2.bottom)), new Point(Math.min(rect1.right, rect2.right), Math.min(rect1.top, rect2.top)));
        return Rectangle.mkEmpty();
    }
    perimeter() {
        const poly = new Polyline();
        poly.addPoint(this.leftTop);
        poly.addPoint(this.rightTop);
        poly.addPoint(this.rightBottom);
        poly.addPoint(this.leftBottom);
        poly.closed = true;
        return poly;
    }
    scaleAroundCenter(scale) {
        this.width = this.width * scale;
        this.height = this.height * scale;
    }
    clone() {
        return Rectangle.mkPP(this.leftTop, this.rightBottom);
    }
    // gets or sets the Size
    get size() {
        return new Size(this.width, this.height);
    }
    set size(value) {
        this.width = value.width;
        this.height = value.height;
    }
    // constructor with Size and center
    static creatRectangleWithSize(size, center) {
        const w = size.width / 2;
        const left = center.x - w;
        const right = center.x + w;
        const h = size.height / 2;
        const bottom = center.y - h;
        const top = center.y + h;
        return new Rectangle({ left: left, right: right, top: top, bottom: bottom });
    }
    // adding a point with a Size
    addPointWithSize(size, point) {
        const w = size.width / 2;
        const h = size.height / 2;
        this.add(new Point(point.x - w, point.y - h));
        this.add(new Point(point.x + w, point.y - h));
        this.add(new Point(point.x - w, point.y + h));
        this.add(new Point(point.x + w, point.y + h));
    }
}
//# sourceMappingURL=rectangle.js.map