2020-06-09 22:32:18 +08:00
|
|
|
|
class Rectangle {
|
|
|
|
|
|
public x: number;
|
|
|
|
|
|
public y: number;
|
|
|
|
|
|
public width: number;
|
|
|
|
|
|
public height: number;
|
|
|
|
|
|
|
2020-06-10 17:41:53 +08:00
|
|
|
|
private _tempMat: Matrix2D;
|
|
|
|
|
|
private _transformMat: Matrix2D;
|
|
|
|
|
|
|
2020-07-07 12:18:51 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取矩形的最大点,即右下角
|
|
|
|
|
|
*/
|
|
|
|
|
|
public get max(){
|
|
|
|
|
|
return new Vector2(this.right, this.bottom);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-10 17:41:53 +08:00
|
|
|
|
public get left() {
|
|
|
|
|
|
return this.x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public get right() {
|
|
|
|
|
|
return this.x + this.width;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public get top() {
|
|
|
|
|
|
return this.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public get bottom() {
|
|
|
|
|
|
return this.y + this.height;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
public get center() {
|
2020-06-16 11:22:37 +08:00
|
|
|
|
return new Vector2(this.x + (this.width / 2), this.y + (this.height / 2));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-10 17:41:53 +08:00
|
|
|
|
public get location() {
|
|
|
|
|
|
return new Vector2(this.x, this.y);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public set location(value: Vector2) {
|
|
|
|
|
|
this.x = value.x;
|
|
|
|
|
|
this.y = value.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
public get size() {
|
|
|
|
|
|
return new Vector2(this.width, this.height);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public set size(value: Vector2) {
|
|
|
|
|
|
this.width = value.x;
|
|
|
|
|
|
this.height = value.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-15 10:42:06 +08:00
|
|
|
|
constructor(x?: number, y?: number, width?: number, height?: number) {
|
|
|
|
|
|
this.x = x ? x : 0;
|
|
|
|
|
|
this.y = y ? y : 0;
|
|
|
|
|
|
this.width = width ? width : 0;
|
|
|
|
|
|
this.height = height ? height : 0;
|
2020-06-09 22:32:18 +08:00
|
|
|
|
}
|
2020-06-10 17:41:53 +08:00
|
|
|
|
|
|
|
|
|
|
public intersects(value: Rectangle) {
|
|
|
|
|
|
return value.left < this.right &&
|
|
|
|
|
|
this.left < value.right &&
|
|
|
|
|
|
value.top < this.bottom &&
|
|
|
|
|
|
this.top < value.bottom;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-12 20:24:51 +08:00
|
|
|
|
public contains(value: Vector2) {
|
|
|
|
|
|
return ((((this.x <= value.x) && (value.x < (this.x + this.width))) &&
|
|
|
|
|
|
(this.y <= value.y)) &&
|
|
|
|
|
|
(value.y < (this.y + this.height)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
public containsRect(value: Rectangle) {
|
|
|
|
|
|
return ((((this.x <= value.x) && (value.x < (this.x + this.width))) &&
|
|
|
|
|
|
(this.y <= value.y)) &&
|
|
|
|
|
|
(value.y < (this.y + this.height)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-19 18:16:42 +08:00
|
|
|
|
public getHalfSize(){
|
|
|
|
|
|
return new Vector2(this.width * 0.5, this.height * 0.5);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-12 20:24:51 +08:00
|
|
|
|
public static fromMinMax(minX: number, minY: number, maxX: number, maxY: number) {
|
|
|
|
|
|
return new Rectangle(minX, minY, maxX - minX, maxY - minY);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
public getClosestPointOnRectangleBorderToPoint(point: Point): { res: Vector2, edgeNormal: Vector2 } {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
let edgeNormal = new Vector2(0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
let res = new Vector2(0, 0);
|
|
|
|
|
|
res.x = MathHelper.clamp(point.x, this.left, this.right);
|
|
|
|
|
|
res.y = MathHelper.clamp(point.y, this.top, this.bottom);
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (this.contains(res)) {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
let dl = res.x - this.left;
|
|
|
|
|
|
let dr = this.right - res.x;
|
|
|
|
|
|
let dt = res.y - this.top;
|
|
|
|
|
|
let db = this.bottom - res.y;
|
|
|
|
|
|
|
2020-06-18 10:49:32 +08:00
|
|
|
|
let min = Math.min(dl, dr, dt, db);
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (min == dt) {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
res.y = this.top;
|
|
|
|
|
|
edgeNormal.y = -1;
|
2020-06-19 09:16:49 +08:00
|
|
|
|
} else if (min == db) {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
res.y = this.bottom;
|
|
|
|
|
|
edgeNormal.y = 1;
|
2020-06-19 09:16:49 +08:00
|
|
|
|
} else if (min == dl) {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
res.x = this.left;
|
|
|
|
|
|
edgeNormal.x = -1;
|
2020-06-19 09:16:49 +08:00
|
|
|
|
} else {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
res.x = this.right;
|
|
|
|
|
|
edgeNormal.x = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (res.x == this.left) {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
edgeNormal.x = -1;
|
|
|
|
|
|
}
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (res.x == this.right) {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
edgeNormal.x = 1;
|
|
|
|
|
|
}
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (res.y == this.top) {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
edgeNormal.y = -1;
|
|
|
|
|
|
}
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (res.y == this.bottom) {
|
2020-06-12 20:24:51 +08:00
|
|
|
|
edgeNormal.y = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
return { res: res, edgeNormal: edgeNormal };
|
2020-06-11 20:36:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-07 12:18:51 +08:00
|
|
|
|
public getClosestPointOnBoundsToOrigin(){
|
|
|
|
|
|
let max = this.max;
|
|
|
|
|
|
let minDist = Math.abs(this.location.x);
|
|
|
|
|
|
let boundsPoint = new Vector2(this.location.x, 0);
|
|
|
|
|
|
|
|
|
|
|
|
if (Math.abs(max.x) < minDist){
|
|
|
|
|
|
minDist = Math.abs(max.x);
|
|
|
|
|
|
boundsPoint.x = max.x;
|
|
|
|
|
|
boundsPoint.y = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (Math.abs(max.y) < minDist){
|
|
|
|
|
|
minDist = Math.abs(max.y);
|
|
|
|
|
|
boundsPoint.x = 0;
|
|
|
|
|
|
boundsPoint.y = max.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (Math.abs(this.location.y) < minDist){
|
|
|
|
|
|
minDist = Math.abs(this.location.y);
|
|
|
|
|
|
boundsPoint.x = 0;
|
|
|
|
|
|
boundsPoint.y = this.location.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return boundsPoint;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-10 17:41:53 +08:00
|
|
|
|
public calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2,
|
|
|
|
|
|
rotation: number, width: number, height: number) {
|
|
|
|
|
|
if (rotation == 0) {
|
|
|
|
|
|
this.x = parentPosition.x + position.x - origin.x * scale.x;
|
|
|
|
|
|
this.y = parentPosition.y + position.y - origin.y * scale.y;
|
|
|
|
|
|
this.width = width * scale.x;
|
|
|
|
|
|
this.height = height * scale.y;
|
2020-06-12 20:24:51 +08:00
|
|
|
|
} else {
|
2020-06-10 17:41:53 +08:00
|
|
|
|
let worldPosX = parentPosition.x + position.x;
|
|
|
|
|
|
let worldPosY = parentPosition.y + position.y;
|
|
|
|
|
|
|
|
|
|
|
|
this._transformMat = Matrix2D.createTranslation(-worldPosX - origin.x, -worldPosY - origin.y);
|
|
|
|
|
|
this._tempMat = Matrix2D.createScale(scale.x, scale.y);
|
|
|
|
|
|
this._transformMat = Matrix2D.multiply(this._transformMat, this._tempMat);
|
|
|
|
|
|
this._tempMat = Matrix2D.createRotation(rotation);
|
|
|
|
|
|
this._transformMat = Matrix2D.multiply(this._transformMat, this._tempMat);
|
|
|
|
|
|
this._tempMat = Matrix2D.createTranslation(worldPosX, worldPosY);
|
|
|
|
|
|
this._transformMat = Matrix2D.multiply(this._transformMat, this._tempMat);
|
|
|
|
|
|
|
|
|
|
|
|
let topLeft = new Vector2(worldPosX, worldPosY);
|
|
|
|
|
|
let topRight = new Vector2(worldPosX + width, worldPosY);
|
|
|
|
|
|
let bottomLeft = new Vector2(worldPosX, worldPosY + height);
|
|
|
|
|
|
let bottomRight = new Vector2(worldPosX + width, worldPosY + height);
|
|
|
|
|
|
|
2020-06-19 18:16:42 +08:00
|
|
|
|
topLeft = Vector2Ext.transformR(topLeft, this._transformMat);
|
|
|
|
|
|
topRight = Vector2Ext.transformR(topRight, this._transformMat);
|
|
|
|
|
|
bottomLeft = Vector2Ext.transformR(bottomLeft, this._transformMat);
|
|
|
|
|
|
bottomRight = Vector2Ext.transformR(bottomRight, this._transformMat);
|
2020-06-10 17:41:53 +08:00
|
|
|
|
|
2020-06-18 10:49:32 +08:00
|
|
|
|
let minX = Math.min(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
|
|
|
|
|
|
let maxX = Math.max(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
|
|
|
|
|
|
let minY = Math.min(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
|
|
|
|
|
|
let maxY = Math.max(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
|
2020-06-10 17:41:53 +08:00
|
|
|
|
|
|
|
|
|
|
this.location = new Vector2(minX, minY);
|
|
|
|
|
|
this.width = maxX - minX;
|
|
|
|
|
|
this.height = maxY - minY;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-06-16 11:22:37 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 给定多边形的点,计算边界
|
|
|
|
|
|
* @param points
|
|
|
|
|
|
*/
|
2020-06-19 09:16:49 +08:00
|
|
|
|
public static rectEncompassingPoints(points: Vector2[]) {
|
2020-06-16 11:22:37 +08:00
|
|
|
|
let minX = Number.POSITIVE_INFINITY;
|
|
|
|
|
|
let minY = Number.POSITIVE_INFINITY;
|
|
|
|
|
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
|
|
|
|
let maxY = Number.NEGATIVE_INFINITY;
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
for (let i = 0; i < points.length; i++) {
|
2020-06-16 11:22:37 +08:00
|
|
|
|
let pt = points[i];
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (pt.x < minX) {
|
2020-06-16 11:22:37 +08:00
|
|
|
|
minX = pt.x;
|
|
|
|
|
|
}
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (pt.x > maxX) {
|
2020-06-16 11:22:37 +08:00
|
|
|
|
maxX = pt.x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (pt.y < minY) {
|
2020-06-16 11:22:37 +08:00
|
|
|
|
minY = pt.y;
|
|
|
|
|
|
}
|
2020-06-19 09:16:49 +08:00
|
|
|
|
if (pt.y > maxY) {
|
2020-06-16 11:22:37 +08:00
|
|
|
|
maxY = pt.y;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return this.fromMinMax(minX, minY, maxX, maxY);
|
|
|
|
|
|
}
|
2020-06-09 22:32:18 +08:00
|
|
|
|
}
|