import { lineIntersectsLine } from "./Utils.js";
/**
* Rectangle class
* TODO maybe look at https://dxr.mozilla.org/mozilla-beta/source/toolkit/modules/Geometry.jsm
*/
class Rectangle {
/**
* @param {number} x
* @param {number} y
* @param {number} w width
* @param {number} h height
*/
constructor(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
/**
* @readonly
*/
get x1() {
return this.x;
}
/**
* @readonly
*/
get y1() {
return this.y;
}
/**
* @readonly
*/
get x2() {
return this.x + this.w;
}
/**
* @readonly
*/
get y2() {
return this.y + this.h;
}
set x1(v) {
this.x = v;
}
set y1(v) {
this.y = v;
}
set x2(v) {
this.w = v - this.x;
}
set y2(v) {
this.h = v - this.y;
}
/**
* @readonly
*/
get center() {
return {
x: this.x + this.w * 0.5,
y: this.y + this.h * 0.5,
};
}
/**
* clone this instance
* @return {Rectangle}
*/
clone() {
return new Rectangle(this.x, this.y, this.w, this.h);
}
/**
* shrink the rectangle from each side by amount x on the x-axis and amount y on the y-axis
* if y is null, y is set to the value of x
* @param {number} x
* @param {number} [y=null]
* @return {Rectangle}
*/
shrink(x, y = null) {
if (y == null) y = x;
this.x += x;
this.y += y;
this.w -= x * 2;
this.h -= y * 2;
return this;
}
/**
* multiply position and size of the rectangle by amount x on the x-axis and amount y on the y-axis
* if y is null, y is set to the value of x
* @param {number} x
* @param {number} [y=null]
* @return {Rectangle}
*/
multiply(x, y = null) {
if (y == null) y = x;
this.x *= x;
this.y *= y;
this.w *= x;
this.h *= y;
return this;
}
/**
* multiply the size of the rectangle by amount x on the x-axis and amount y on the y-axis
* if y is null, y is set to the value of x
* @param {number} x
* @param {number} [y=null]
* @return {Rectangle}
*/
scale(x, y = null) {
if (y == null) y = x;
this.w *= x;
this.h *= y;
return this;
}
/**
* Check if the given Point (x,y) is inside the rectangle, padding is added in each direction
* @param {number} x
* @param {number} y
* @param {number} pad padding
* @return {boolean}
*/
contains(x, y, pad = 0) {
return x > this.x1 - pad && x < this.x2 + pad && y > this.y1 - pad && y < this.y2 + pad;
}
/**
* get the lines of this rectangle as a nested array of line-points, clockwise
* e.g. [[[0,0],[10,0]], [[10,0],[10,10]], [[10,10],[0,10]], [[0,10],[0,0]]]
* @return {Array}
*/
getLines() {
return [
this.getTopLine(),
this.getRightLine(),
this.getBottomLine(),
this.getLeftLine()
];
}
getTopLine() {
return [
[this.x1, this.y1],
[this.x2, this.y1]
]
}
getBottomLine() {
return [
[this.x2, this.y2],
[this.x1, this.y2]
]
}
getLeftLine() {
return [
[this.x1, this.y2],
[this.x1, this.y1]
]
}
getRightLine() {
return [
[this.x2, this.y1],
[this.x2, this.y2]
]
}
/**
* check if this rectangle intersects or contains the given line from Point (x1,y1) to Point (x2, y2)
*
* @param {number} x1
* @param {number} y1
* @param {number} x2
* @param {number} y2
* @param {number} pad padding
* @return {boolean}
*/
intersectsLine(x1, y1, x2, y2, pad = 0) {
return lineIntersectsLine(x1, y1, x2, y2, this.x1 - pad, this.y1 - pad, this.x1 - pad, this.y2 + pad) ||
lineIntersectsLine(x1, y1, x2, y2, this.x2 + pad, this.y1 - pad, this.x2 + pad, this.y2 + pad) ||
lineIntersectsLine(x1, y1, x2, y2, this.x1 - pad, this.y1 - pad, this.x2 + pad, this.y1 - pad) ||
lineIntersectsLine(x1, y1, x2, y2, this.x1 - pad, this.y2 + pad, this.x2 + pad, this.y2 + pad) ||
this.contains(x1, y1, pad) ||
this.contains(x2, y2, pad);
}
/**
* check if this rectangle intersects the given Rectangle
*
* @param {Rectangle} other
* @return {boolean}
*/
intersectsRect(other) {
let x1 = Math.max(this.x1, other.x1);
let x2 = Math.min(this.x2, other.x2);
let y1 = Math.max(this.y1, other.y1);
let y2 = Math.min(this.y2, other.y2);
return x1 < x2 && y1 < y2;
}
}
export default Rectangle;