141 lines
3.6 KiB
TypeScript
141 lines
3.6 KiB
TypeScript
import { Vector } from "../Common/vector";
|
|
|
|
|
|
|
|
// 包围盒类型
|
|
export type BoundingRect = {
|
|
x: number;
|
|
y: number;
|
|
width: number;
|
|
height: number;
|
|
};
|
|
|
|
|
|
// 包围盒操作
|
|
export const Bound = {
|
|
|
|
/**
|
|
* 从点集生成包围盒
|
|
* @param points
|
|
*/
|
|
fromPoints(points: Array<[number, number]>): BoundingRect {
|
|
let maxX = -Infinity,
|
|
minX = Infinity,
|
|
maxY = -Infinity,
|
|
minY = Infinity;
|
|
|
|
points.map(item => {
|
|
if(item[0] > maxX) maxX = item[0];
|
|
if(item[0] < minX) minX = item[0];
|
|
if(item[1] > maxY) maxY = item[1];
|
|
if(item[1] < minY) minY = item[1];
|
|
});
|
|
|
|
return {
|
|
x: minX,
|
|
y: minY,
|
|
width: maxX - minX,
|
|
height: maxY - minY
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 由包围盒转化为四个顶点(顺时针)
|
|
* @param bound
|
|
*/
|
|
toPoints(bound: BoundingRect): Array<[number, number]> {
|
|
return [
|
|
[bound.x, bound.y],
|
|
[bound.x + bound.width, bound.y],
|
|
[bound.x + bound.width, bound.y + bound.height],
|
|
[bound.x, bound.y + bound.height]
|
|
];
|
|
},
|
|
|
|
/**
|
|
* 求包围盒并集
|
|
* @param arg
|
|
*/
|
|
union(...arg: BoundingRect[]): BoundingRect {
|
|
return arg.length > 1?
|
|
arg.reduce((total, cur) => {
|
|
let minX = total.x < cur.x? total.x: cur.x,
|
|
maxX = total.x + total.width < cur.x + cur.width? cur.x + cur.width: total.x + total.width,
|
|
minY = total.y < cur.y? total.y: cur.y,
|
|
maxY = total.y + total.height < cur.y + cur.height? cur.y + cur.height: total.y + total.height;
|
|
|
|
return {
|
|
x: minX,
|
|
y: minY,
|
|
width: maxX - minX,
|
|
height: maxY - minY
|
|
};
|
|
}): arg[0];
|
|
},
|
|
|
|
/**
|
|
* 包围盒求交集
|
|
* @param b1
|
|
* @param b2
|
|
*/
|
|
intersect(b1: BoundingRect, b2: BoundingRect): BoundingRect {
|
|
let x, y,
|
|
maxX, maxY,
|
|
overlapsX,
|
|
overlapsY;
|
|
|
|
if(b1.x < b2.x + b2.width && b1.x + b1.width > b2.x) {
|
|
x = b1.x < b2.x? b2.x: b1.x;
|
|
maxX = b1.x + b1.width < b2.x + b2.width? b1.x + b1.width: b2.x + b2.width;
|
|
overlapsX = maxX - x;
|
|
}
|
|
|
|
if(b1.y < b2.y + b2.height && b1.y + b1.height > b2.y) {
|
|
y = b1.y < b2.y? b2.y: b1.y;
|
|
maxY = b1.y + b1.height < b2.y + b2.height? b1.y + b1.height: b2.y + b2.height;
|
|
overlapsY = maxY - y;
|
|
}
|
|
|
|
if(!overlapsX || !overlapsY) return null;
|
|
|
|
return {
|
|
x,
|
|
y,
|
|
width: overlapsX,
|
|
height: overlapsY
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 求包围盒旋转后新形成的包围盒
|
|
* @param bound
|
|
* @param rot
|
|
*/
|
|
rotation(bound: BoundingRect, rot: number): BoundingRect {
|
|
let cx = bound.x + bound.width / 2,
|
|
cy = bound.y + bound.height / 2;
|
|
|
|
return Bound.fromPoints(Bound.toPoints(bound).map(item => Vector.rotation(rot, item, [cx, cy])));
|
|
},
|
|
|
|
/**
|
|
* 判断两个包围盒是否相交
|
|
* @param b1
|
|
* @param b2
|
|
*/
|
|
isOverlap(b1: BoundingRect, b2: BoundingRect): boolean {
|
|
let maxX1 = b1.x + b1.width,
|
|
maxY1 = b1.y + b1.height,
|
|
maxX2 = b2.x + b2.width,
|
|
maxY2 = b2.y + b2.height;
|
|
|
|
if (b1.x < maxX2 && b2.x < maxX1 && b1.y < maxY2 && b2.y < maxY1) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|