UNPKG

4.65 kBJavaScriptView Raw
1import { __read, __spreadArray } from "tslib";
2function dot(a, b) {
3 return (a[0] || 0) * (b[0] || 0) + (a[1] || 0) * (b[1] || 0) + (a[2] || 0) * (b[2] || 0);
4}
5/**
6 * @private
7 * 1. 获取投影轴
8 */
9function getAxes(points /** 多边形的关键点 */) {
10 // 目前先处理 平行矩形 的场景, 其他多边形不处理
11 if (points.length > 4) {
12 return [];
13 }
14 // 获取向量
15 var vector = function (start, end) {
16 return [end.x - start.x, end.y - start.y];
17 };
18 // 由于 矩形的平行原理,所以只有 2 条投影轴: A -> B, B -> C
19 var AB = vector(points[0], points[1]);
20 var BC = vector(points[1], points[2]);
21 return [AB, BC];
22}
23/**
24 * @private
25 * 绕指定点顺时针旋转后的点坐标
26 * 默认绕原点旋转
27 */
28function rotateAtPoint(point, deg, origin) {
29 if (deg === void 0) { deg = 0; }
30 if (origin === void 0) { origin = { x: 0, y: 0 }; }
31 var x = point.x, y = point.y;
32 return {
33 x: (x - origin.x) * Math.cos(-deg) + (y - origin.y) * Math.sin(-deg) + origin.x,
34 y: (origin.x - x) * Math.sin(-deg) + (y - origin.y) * Math.cos(-deg) + origin.y,
35 };
36}
37/**
38 * @private
39 * 转化为顶点坐标数组
40 *
41 * @param {Object} box
42 */
43function getRectPoints(box) {
44 var points = [
45 { x: box.x, y: box.y },
46 { x: box.x + box.width, y: box.y },
47 { x: box.x + box.width, y: box.y + box.height },
48 { x: box.x, y: box.y + box.height },
49 ];
50 var rotation = box.rotation;
51 if (rotation) {
52 return [
53 rotateAtPoint(points[0], rotation, points[0]),
54 rotateAtPoint(points[1], rotation, points[0]),
55 rotateAtPoint(points[2], rotation, points[0]),
56 rotateAtPoint(points[3], rotation, points[0]),
57 ];
58 }
59 return points;
60}
61/**
62 * @private
63 * 2. 获取多边形在投影轴上的投影
64 *
65 * 向量的点积的其中一个几何含义是:一个向量在平行于另一个向量方向上的投影的数值乘积。
66 * 由于投影轴是单位向量(长度为1),投影的长度为 x1 * x2 + y1 * y2
67 */
68function getProjection(points /** 多边形的关键点 */, axis) {
69 // 目前先处理矩形的场景
70 if (points.length > 4) {
71 return { min: 0, max: 0 };
72 }
73 var scalars = [];
74 points.forEach(function (point) {
75 scalars.push(dot([point.x, point.y], axis));
76 });
77 return { min: Math.min.apply(Math, __spreadArray([], __read(scalars), false)), max: Math.max.apply(Math, __spreadArray([], __read(scalars), false)) };
78}
79function isProjectionOverlap(projection1, projection2) {
80 return projection1.max > projection2.min && projection1.min < projection2.max;
81}
82function isValidNumber(d) {
83 return typeof d === 'number' && !Number.isNaN(d) && d !== Infinity && d !== -Infinity;
84}
85function isValidBox(box) {
86 return ['x', 'y', 'width', 'height'].every(function (attr) { return isValidNumber(box[attr]); });
87}
88/**
89 * 快速判断两个无旋转矩形是否遮挡
90 */
91export function isIntersectRect(box1, box2, margin) {
92 if (margin === void 0) { margin = 0; }
93 return !(box2.x > box1.x + box1.width + margin ||
94 box2.x + box2.width < box1.x - margin ||
95 box2.y > box1.y + box1.height + margin ||
96 box2.y + box2.height < box1.y - margin);
97}
98/**
99 * detect whether two shape is intersected, useful when shape is been rotated
100 * 判断两个矩形是否重叠(相交和包含, 是否旋转)
101 *
102 * - 原理: 分离轴定律
103 */
104export function intersect(box1, box2, margin) {
105 if (margin === void 0) { margin = 0; }
106 // 如果两个 box 中有一个是不合法的 box,也就是不会被渲染出来的,那么它们就不相交。
107 if (!isValidBox(box1) || !isValidBox(box2))
108 return false;
109 // 如果两个矩形没有旋转,使用快速判断
110 if (!box1.rotation && !box2.rotation) {
111 return isIntersectRect(box1, box2, margin);
112 }
113 // 分别获取 4 个关键点
114 var rect1Points = getRectPoints(box1);
115 var rect2Points = getRectPoints(box2);
116 // 获取所有投影轴
117 var axes = getAxes(rect1Points).concat(getAxes(rect2Points));
118 for (var i = 0; i < axes.length; i++) {
119 var axis = axes[i];
120 var projection1 = getProjection(rect1Points, axis);
121 var projection2 = getProjection(rect2Points, axis);
122 // 判断投影轴上的投影是否存在重叠,若检测到存在间隙则立刻退出判断,消除不必要的运算。
123 if (!isProjectionOverlap(projection1, projection2)) {
124 return false;
125 }
126 }
127 return true;
128}
129//# sourceMappingURL=collision-detect.js.map
\No newline at end of file