|
@@ -1,10 +1,11 @@
|
|
|
import { Vector2, ShapeUtils, Box2 } from "three";
|
|
|
import { Transform } from "konva/lib/Util";
|
|
|
-import { round } from "./shared.ts";
|
|
|
+import { flatPositions, round } from "./shared.ts";
|
|
|
import { IRect } from "konva/lib/types";
|
|
|
+import { diff as diffPolygons, MultiPolygon } from "martinez-polygon-clipping";
|
|
|
|
|
|
export type Pos = { x: number; y: number };
|
|
|
-export type Size = { width: number, height: number }
|
|
|
+export type Size = { width: number; height: number };
|
|
|
|
|
|
export const vector = (pos: Pos = { x: 0, y: 0 }): Vector2 => {
|
|
|
return new Vector2(pos.x, pos.y);
|
|
@@ -130,9 +131,9 @@ export function getPolygonDirection(points: Pos[]) {
|
|
|
let area = 0;
|
|
|
const numPoints = points.length;
|
|
|
for (let i = 0; i < numPoints; i++) {
|
|
|
- const p1 = points[i];
|
|
|
- const p2 = points[(i + 1) % numPoints];
|
|
|
- area += (p2.x - p1.x) * (p2.y + p1.y);
|
|
|
+ const p1 = points[i];
|
|
|
+ const p2 = points[(i + 1) % numPoints];
|
|
|
+ area += (p2.x - p1.x) * (p2.y + p1.y);
|
|
|
}
|
|
|
|
|
|
// 如果面积为正,是逆时针;否则是顺时针
|
|
@@ -174,19 +175,18 @@ export const lineAndVectorIncludedAngle = (line: Pos[], v: Pos) =>
|
|
|
* @returns
|
|
|
*/
|
|
|
export const lineCenter = (line: Pos[]) => {
|
|
|
- const start = vector(line[0])
|
|
|
+ const start = vector(line[0]);
|
|
|
for (let i = 1; i < line.length; i++) {
|
|
|
- start.add(line[i])
|
|
|
+ start.add(line[i]);
|
|
|
}
|
|
|
return start.multiplyScalar(1 / line.length);
|
|
|
-}
|
|
|
-
|
|
|
+};
|
|
|
|
|
|
export const lineSpeed = (line: Pos[], step: number) => {
|
|
|
- const p = vector(line[0])
|
|
|
- const v = vector(line[1]).sub(line[0])
|
|
|
- return p.add(v.multiplyScalar(step))
|
|
|
-}
|
|
|
+ const p = vector(line[0]);
|
|
|
+ const v = vector(line[1]).sub(line[0]);
|
|
|
+ return p.add(v.multiplyScalar(step));
|
|
|
+};
|
|
|
|
|
|
export const pointsCenter = (points: Pos[]) => {
|
|
|
if (points.length === 0) return { x: 0, y: 0 };
|
|
@@ -371,15 +371,15 @@ export const lineInner = (line: Pos[], position: Pos) => {
|
|
|
return false;
|
|
|
}
|
|
|
// 检查点 P 的坐标是否在 A 和 B 的坐标范围内
|
|
|
- const minX = Math.min(A.x, B.x)
|
|
|
- const maxX = Math.max(A.x, B.x)
|
|
|
- const minY = Math.min(A.y, B.y)
|
|
|
- const maxY = Math.max(A.y, B.y)
|
|
|
+ const minX = Math.min(A.x, B.x);
|
|
|
+ const maxX = Math.max(A.x, B.x);
|
|
|
+ const minY = Math.min(A.y, B.y);
|
|
|
+ const maxY = Math.max(A.y, B.y);
|
|
|
return (
|
|
|
(minX < P.x || numEq(minX, P.x)) &&
|
|
|
(P.x < maxX || numEq(maxX, P.x)) &&
|
|
|
(minY < P.y || numEq(minY, P.y)) &&
|
|
|
- (P.y < maxY || numEq(maxY, P.y))
|
|
|
+ (P.y < maxY || numEq(maxY, P.y))
|
|
|
);
|
|
|
};
|
|
|
|
|
@@ -453,7 +453,6 @@ export const isPolygonLineIntersect = (polygon: Pos[], line: Pos[]) => {
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* 判断点是否在多边形内部
|
|
|
* @param polygon 多边形顶点数组,按顺时针或逆时针顺序排列
|
|
@@ -463,32 +462,32 @@ export const isPolygonLineIntersect = (polygon: Pos[], line: Pos[]) => {
|
|
|
export const isPolygonPointInner = (polygon: Pos[], pos: Pos): boolean => {
|
|
|
// 如果多边形少于3个点,直接返回false
|
|
|
if (polygon.length < 3) return false;
|
|
|
-
|
|
|
+
|
|
|
let inside = false;
|
|
|
const x = pos.x;
|
|
|
const y = pos.y;
|
|
|
-
|
|
|
+
|
|
|
// 使用射线法判断
|
|
|
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
|
const xi = polygon[i].x;
|
|
|
const yi = polygon[i].y;
|
|
|
const xj = polygon[j].x;
|
|
|
const yj = polygon[j].y;
|
|
|
-
|
|
|
+
|
|
|
// 检查点是否在多边形的顶点上
|
|
|
if ((numEq(xi, x) && numEq(yi, y)) || (numEq(xj, x) && numEq(yj, y))) {
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 检查点是否在边的水平射线上
|
|
|
- const intersect = ((yi > y) !== (yj > y)) &&
|
|
|
- (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
|
|
-
|
|
|
+ const intersect =
|
|
|
+ yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
|
|
|
+
|
|
|
if (intersect) {
|
|
|
inside = !inside;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return inside;
|
|
|
};
|
|
|
|
|
@@ -593,50 +592,68 @@ export const getLineRelationMat = (l1: [Pos, Pos], l2: [Pos, Pos]) => {
|
|
|
.rotate(angle)
|
|
|
.translate(-P1.x, -P1.y);
|
|
|
|
|
|
-
|
|
|
if (!eqPoint(mat.point(P1), P2)) {
|
|
|
- console.error('对准不正确 旋转后P1', mat.point(P1), P2)
|
|
|
+ console.error("对准不正确 旋转后P1", mat.point(P1), P2);
|
|
|
}
|
|
|
if (!eqPoint(mat.point(P1End), P2End)) {
|
|
|
- console.error('对准不正确 旋转后P2', mat.point(P1End), P1End)
|
|
|
+ console.error("对准不正确 旋转后P2", mat.point(P1End), P1End);
|
|
|
}
|
|
|
- return mat
|
|
|
+ return mat;
|
|
|
};
|
|
|
|
|
|
// 判断两向量是否垂直
|
|
|
export const isVertical = (v1: Pos, v2: Pos) => {
|
|
|
- console.log(vector(v1).dot(v2))
|
|
|
- return zeroEq(vector(v1).dot(v2))
|
|
|
-}
|
|
|
+ console.log(vector(v1).dot(v2));
|
|
|
+ return zeroEq(vector(v1).dot(v2));
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
* 判断rect1是否完整包含rect2
|
|
|
- * @param rect1
|
|
|
- * @param rect2
|
|
|
- * @returns
|
|
|
+ * @param rect1
|
|
|
+ * @param rect2
|
|
|
+ * @returns
|
|
|
*/
|
|
|
export const isRectContained = (rect1: IRect, rect2: IRect) => {
|
|
|
// 计算 rect1 的左右边界
|
|
|
const rect1Left = Math.min(rect1.x, rect1.x + rect1.width);
|
|
|
const rect1Right = Math.max(rect1.x, rect1.x + rect1.width);
|
|
|
-
|
|
|
+
|
|
|
// 计算 rect1 的上下边界
|
|
|
const rect1Top = Math.min(rect1.y, rect1.y + rect1.height);
|
|
|
const rect1Bottom = Math.max(rect1.y, rect1.y + rect1.height);
|
|
|
-
|
|
|
+
|
|
|
// 计算 rect2 的左右边界
|
|
|
const rect2Left = Math.min(rect2.x, rect2.x + rect2.width);
|
|
|
const rect2Right = Math.max(rect2.x, rect2.x + rect2.width);
|
|
|
-
|
|
|
+
|
|
|
// 计算 rect2 的上下边界
|
|
|
const rect2Top = Math.min(rect2.y, rect2.y + rect2.height);
|
|
|
const rect2Bottom = Math.max(rect2.y, rect2.y + rect2.height);
|
|
|
-
|
|
|
+
|
|
|
// 检查 rect2 是否完全在 rect1 内
|
|
|
return (
|
|
|
- rect2Left >= rect1Left &&
|
|
|
- rect2Right <= rect1Right &&
|
|
|
- rect2Top >= rect1Top &&
|
|
|
- rect2Bottom <= rect1Bottom
|
|
|
+ rect2Left >= rect1Left &&
|
|
|
+ rect2Right <= rect1Right &&
|
|
|
+ rect2Top >= rect1Top &&
|
|
|
+ rect2Bottom <= rect1Bottom
|
|
|
);
|
|
|
-}
|
|
|
+};
|
|
|
+
|
|
|
+export const getDiffPolygons = (
|
|
|
+ originPolygon: Pos[],
|
|
|
+ targetPolygons: Pos[][]
|
|
|
+) => {
|
|
|
+ const geo1 = originPolygon.map(({ x, y }) => [x, y]);
|
|
|
+ geo1.push(geo1[0])
|
|
|
+ const geo2s = targetPolygons.map((targetPolygon) => {
|
|
|
+ const geo2 = targetPolygon.map(({ x, y }) => [x, y]);
|
|
|
+ geo2.push(geo2[0]);
|
|
|
+ return geo2;
|
|
|
+ });
|
|
|
+
|
|
|
+ const subGeos = diffPolygons([geo1], geo2s);
|
|
|
+ return subGeos.map((mulPolygon) => {
|
|
|
+ const polygon = mulPolygon as number[][][];
|
|
|
+ return polygon[0].map((position) => ({ x: position[0], y: position[1] }));
|
|
|
+ }) as Pos[][];
|
|
|
+};
|