|
@@ -9,6 +9,8 @@ import {
|
|
|
getVerticalDire,
|
|
|
createLineByDire,
|
|
|
getLineProjection,
|
|
|
+ RelationshipEnum,
|
|
|
+ round,
|
|
|
} from "../../../shared/math";
|
|
|
import {
|
|
|
WholeLineAttrib,
|
|
@@ -20,15 +22,21 @@ import {
|
|
|
WHOLE_LINE_POINT_MERGE_DIST,
|
|
|
} from "./constant";
|
|
|
import {
|
|
|
+ generateWholeLineLineId,
|
|
|
generateWholeLinePointId,
|
|
|
+ generateWholeLinePoygonId,
|
|
|
+ getWholeLineLineRaw,
|
|
|
getWholeLineLinesRawByPointId,
|
|
|
getWholeLinePoint,
|
|
|
getWholeLinePoints,
|
|
|
getWholeLinePolygonLines,
|
|
|
getWholeLinePolygonLinesByPoint,
|
|
|
+ wholeLineDelLineByPointIds,
|
|
|
wholeLineLineAddPoint,
|
|
|
+ wholeLineLineIsolatePoint,
|
|
|
wholeLineReplacePoint,
|
|
|
} from "./whole-line-base";
|
|
|
+import { wholeLineAddPoint } from "./whole-line-mouse";
|
|
|
|
|
|
export const repeatablePushWholeLinePoint = (config: WholeLineAttrib) => {
|
|
|
let maxId = Math.max(...config.points.map((point) => Number(point.id) || 0));
|
|
@@ -107,7 +115,8 @@ export const repeatableWholeLineLineIntersections = (
|
|
|
const b = otherLine;
|
|
|
const intersection = getLineIntersection(
|
|
|
[a[0].x, a[0].y, a[1].x, a[1].y],
|
|
|
- [b[0].x, b[0].y, b[1].x, b[1].y]
|
|
|
+ [b[0].x, b[0].y, b[1].x, b[1].y],
|
|
|
+ [RelationshipEnum.Intersect]
|
|
|
);
|
|
|
if (intersection) {
|
|
|
if (DEV) {
|
|
@@ -455,23 +464,49 @@ export const mergeWholeLinePointsByPoint = (
|
|
|
* @param initPosition 线段初始位置
|
|
|
* @param move 移动向量
|
|
|
*/
|
|
|
-export const moveWholeLineLine = (
|
|
|
+export const repeatMoveWholeLineLine = (
|
|
|
config: WholeLineAttrib,
|
|
|
lineAttrib: WholeLineLineAttrib,
|
|
|
initPosition: number[][],
|
|
|
- move: number[],
|
|
|
- maxAngle = 160
|
|
|
+ angleRang = [10, 170]
|
|
|
) => {
|
|
|
- console.log(lineAttrib);
|
|
|
+ const cache: {
|
|
|
+ [key in string]: {
|
|
|
+ id: string;
|
|
|
+ split: boolean;
|
|
|
+ refDire: number[];
|
|
|
+ lineDire: number[];
|
|
|
+ isFirst: boolean;
|
|
|
+ };
|
|
|
+ } = {};
|
|
|
const linePointIds = lineAttrib.pointIds;
|
|
|
- const moveDire = new Vector2(move[0], move[1]).normalize().toArray();
|
|
|
- const pointJointLineDires: (number[] | null)[] = [];
|
|
|
- const poinJointLineIds: (string | null)[] = [];
|
|
|
- const isSplitPoints: boolean[] = [];
|
|
|
-
|
|
|
- // 获取参考线段,夹角最小,雨move向量夹角最小的优先
|
|
|
- for (let i = 0; i < 2; i++) {
|
|
|
- const curPointId = linePointIds[i];
|
|
|
+ const line0 = getWholeLinePoints(config, [linePointIds[0], linePointIds[1]]);
|
|
|
+ const lineDire0 = getLineDire([
|
|
|
+ line0[0].x,
|
|
|
+ line0[0].y,
|
|
|
+ line0[1].x,
|
|
|
+ line0[1].y,
|
|
|
+ ]);
|
|
|
+ const line1 = getWholeLinePoints(config, [linePointIds[1], linePointIds[0]]);
|
|
|
+ const lineDire1 = getLineDire([
|
|
|
+ line1[0].x,
|
|
|
+ line1[0].y,
|
|
|
+ line1[1].x,
|
|
|
+ line1[1].y,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ const getPointRefInfo = (moveDire: number[], ndx: number) => {
|
|
|
+ let isFirst = true;
|
|
|
+ const curPointId = linePointIds[ndx];
|
|
|
+ if (!cache[curPointId]) {
|
|
|
+ cache[curPointId] = {} as any;
|
|
|
+ } else {
|
|
|
+ isFirst = false;
|
|
|
+ // if (cache[curPointId].split) {
|
|
|
+ return { ...cache[curPointId], isFirst };
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
const joinLines = getWholeLineLinesRawByPointId(config, curPointId).filter(
|
|
|
(line) =>
|
|
|
!(
|
|
@@ -479,12 +514,8 @@ export const moveWholeLineLine = (
|
|
|
line.pointIds.includes(linePointIds[1])
|
|
|
)
|
|
|
);
|
|
|
-
|
|
|
- const line = getWholeLinePoints(config, [
|
|
|
- linePointIds[i],
|
|
|
- linePointIds[i === 0 ? 1 : 0],
|
|
|
- ]);
|
|
|
- const lineDire = getLineDire([line[0].x, line[0].y, line[1].x, line[1].y]);
|
|
|
+ const joinLineDires: number[][] = [];
|
|
|
+ const lineDire = ndx === 0 ? lineDire0 : lineDire1;
|
|
|
|
|
|
let invAngle = Number.MAX_VALUE;
|
|
|
let invSelectLineId: string;
|
|
@@ -492,12 +523,12 @@ export const moveWholeLineLine = (
|
|
|
|
|
|
let alongAngle = -Number.MAX_VALUE;
|
|
|
let alongSelectLineId: string;
|
|
|
- let alongSelectLineDire: number[] | null;
|
|
|
+ let alongSelectLineDire: number[] | null = null;
|
|
|
|
|
|
for (let { pointIds: joinPointIds, id } of joinLines) {
|
|
|
joinPointIds = [
|
|
|
- linePointIds[i],
|
|
|
- ...joinPointIds.filter((id) => id !== linePointIds[i]),
|
|
|
+ linePointIds[ndx],
|
|
|
+ ...joinPointIds.filter((id) => id !== linePointIds[ndx]),
|
|
|
];
|
|
|
const joinLine = getWholeLinePoints(config, joinPointIds);
|
|
|
const joinLineDire = getLineDire([
|
|
@@ -506,6 +537,7 @@ export const moveWholeLineLine = (
|
|
|
joinLine[1].x,
|
|
|
joinLine[1].y,
|
|
|
]);
|
|
|
+ joinLineDires.push(joinLineDire);
|
|
|
// if (["10", "14"].includes(id)) {
|
|
|
// continue;
|
|
|
// }
|
|
@@ -533,8 +565,8 @@ export const moveWholeLineLine = (
|
|
|
|
|
|
if (!invSelectLineDire || !alongSelectLineDire) {
|
|
|
pointJointLineDire = invSelectLineDire || alongSelectLineDire;
|
|
|
- selectLineId = invSelectLineId || alongSelectLineId;
|
|
|
- angle = invAngle | alongAngle;
|
|
|
+ selectLineId = invSelectLineDire ? invSelectLineId : alongSelectLineId;
|
|
|
+ angle = invSelectLineDire ? invAngle : alongAngle;
|
|
|
} else if (
|
|
|
Math.abs(getDire2Angle(moveDire, invSelectLineDire)) <
|
|
|
Math.abs(getDire2Angle(moveDire, alongSelectLineDire))
|
|
@@ -548,59 +580,210 @@ export const moveWholeLineLine = (
|
|
|
angle = alongAngle;
|
|
|
}
|
|
|
|
|
|
- let isSplitPoint = joinLines.length > 2;
|
|
|
+ let isSplitPoint = false;
|
|
|
// 需要判定,如果参考线与当前线段夹角超过多少则不适合作为参考线
|
|
|
+ let refLineAngle = Math.abs(MathUtils.radToDeg(angle));
|
|
|
if (
|
|
|
- pointJointLineDire !== null &&
|
|
|
- Math.abs(MathUtils.radToDeg(angle)) > maxAngle
|
|
|
+ (pointJointLineDire !== null && refLineAngle > angleRang[1]) ||
|
|
|
+ refLineAngle < angleRang[0]
|
|
|
) {
|
|
|
+ console.log(
|
|
|
+ "夹角不在范围,分割",
|
|
|
+ selectLineId,
|
|
|
+ ndx === 0 ? line0 : line1,
|
|
|
+ refLineAngle
|
|
|
+ );
|
|
|
selectLineId = null;
|
|
|
pointJointLineDire = getVerticalDire(pointJointLineDire);
|
|
|
isSplitPoint = true;
|
|
|
+
|
|
|
+ // 如果有多条线段,判断是否方向一致,不一致则要分割
|
|
|
+ } else if (joinLines.length > 1) {
|
|
|
+ const temp = pointJointLineDire;
|
|
|
+ for (let i = 0; i < joinLines.length; i++) {
|
|
|
+ if (temp === joinLineDires[i]) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ const angle =
|
|
|
+ (getDire2Angle(temp, joinLineDires[i]) + Math.PI) % Math.PI;
|
|
|
+
|
|
|
+ if (round(angle, 3) > 0) {
|
|
|
+ console.log("方向不同,分割");
|
|
|
+ isSplitPoint = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ cache[curPointId].refDire = pointJointLineDire;
|
|
|
+ cache[curPointId].lineDire = lineDire;
|
|
|
+ cache[curPointId].id = selectLineId;
|
|
|
+ cache[curPointId].split = isSplitPoint;
|
|
|
+ cache[curPointId].isFirst = isFirst;
|
|
|
+
|
|
|
+ return cache[curPointId];
|
|
|
+ };
|
|
|
+
|
|
|
+ return (move: number[]) => {
|
|
|
+ const moveDire = new Vector2(move[0], move[1]).normalize().toArray();
|
|
|
+ const pointInfos = [
|
|
|
+ getPointRefInfo(moveDire, 0),
|
|
|
+ getPointRefInfo(moveDire, 1),
|
|
|
+ ];
|
|
|
+
|
|
|
+ // console.log(pointInfos);
|
|
|
+ const positions = [
|
|
|
+ [initPosition[0][0] + move[0], initPosition[0][1] + move[1]],
|
|
|
+ [initPosition[1][0] + move[0], initPosition[1][1] + move[1]],
|
|
|
+ ];
|
|
|
+ const pointAttribs = getWholeLinePoints(config, lineAttrib.pointIds);
|
|
|
+ if (pointInfos[0].refDire || pointInfos[1].refDire) {
|
|
|
+ const currentPositions: number[][] = [];
|
|
|
+ const joinDires = pointInfos.map(({ refDire }) =>
|
|
|
+ refDire === null
|
|
|
+ ? pointInfos[0].refDire || pointInfos[1].refDire
|
|
|
+ : refDire
|
|
|
+ );
|
|
|
+
|
|
|
+ for (let i = 0; i < pointInfos.length; i++) {
|
|
|
+ const joinDire = joinDires[i];
|
|
|
+ const isSplit = pointInfos[i].split && pointInfos[i].isFirst;
|
|
|
+ const joinLine = createLineByDire(joinDire, initPosition[i], 10);
|
|
|
+
|
|
|
+ if (isSplit) {
|
|
|
+ const addPointId = generateWholeLinePointId(config);
|
|
|
+ config.points.push({
|
|
|
+ ...pointAttribs[i],
|
|
|
+ id: addPointId,
|
|
|
+ });
|
|
|
+ wholeLineLineIsolatePoint(
|
|
|
+ config,
|
|
|
+ line0,
|
|
|
+ lineAttrib.pointIds[i],
|
|
|
+ addPointId
|
|
|
+ );
|
|
|
+ }
|
|
|
+ currentPositions[i] = getLineProjection(joinLine, positions[i]).point;
|
|
|
+ }
|
|
|
+ const firstMain =
|
|
|
+ getLineDist(currentPositions[0], initPosition[0]) <
|
|
|
+ getLineDist(currentPositions[1], initPosition[1]);
|
|
|
+ const lineDire = firstMain ? lineDire0 : lineDire1;
|
|
|
+ const lineStart = firstMain ? currentPositions[0] : currentPositions[1];
|
|
|
+ const bitDire = firstMain ? joinDires[1] : joinDires[0];
|
|
|
+ const bitStart = firstMain ? initPosition[1] : initPosition[0];
|
|
|
+
|
|
|
+ const main = createLineByDire(lineDire, lineStart, 10);
|
|
|
+ const bit = createLineByDire(bitDire, bitStart, 10);
|
|
|
+ const lineEnd = getLineIntersection(main, bit);
|
|
|
+
|
|
|
+ if (firstMain) {
|
|
|
+ positions[0] = lineStart;
|
|
|
+ positions[1] = lineEnd;
|
|
|
+ } else {
|
|
|
+ positions[1] = lineStart;
|
|
|
+ positions[0] = lineEnd;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- pointJointLineDires.push(pointJointLineDire);
|
|
|
- poinJointLineIds.push(selectLineId);
|
|
|
- isSplitPoints.push(isSplitPoint);
|
|
|
+ pointAttribs[0].x = positions[0][0];
|
|
|
+ pointAttribs[0].y = positions[0][1];
|
|
|
+ pointAttribs[1].x = positions[1][0];
|
|
|
+ pointAttribs[1].y = positions[1][1];
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 修复config数据, 重合点删除,重合线删除
|
|
|
+ * @param config
|
|
|
+ */
|
|
|
+export const fixWholeLineConfig = (config: WholeLineAttrib) => {
|
|
|
+ for (let i = 0; i < config.lines.length; i++) {
|
|
|
+ const line = config.lines[i];
|
|
|
+ const points = getWholeLinePoints(config, line.pointIds);
|
|
|
+ const dist = round(
|
|
|
+ getLineDist([points[0].x, points[0].y], [points[1].x, points[1].y]),
|
|
|
+ 4
|
|
|
+ );
|
|
|
+ if (dist !== 0) continue;
|
|
|
+ const change = wholeLineReplacePoint(config, [points[1].id], points[0].id);
|
|
|
+ i = Math.max(i - change.lineChange.del.length, 0);
|
|
|
}
|
|
|
|
|
|
- const positions = [
|
|
|
- [initPosition[0][0] + move[0], initPosition[0][1] + move[1]],
|
|
|
- [initPosition[1][0] + move[0], initPosition[1][1] + move[1]],
|
|
|
- ];
|
|
|
- const pointAttribs = getWholeLinePoints(config, lineAttrib.pointIds);
|
|
|
- if (pointJointLineDires[0] || !pointJointLineDires[1]) {
|
|
|
- for (let i = 0; i < pointJointLineDires.length; i++) {
|
|
|
- const joinDire =
|
|
|
- pointJointLineDires[i] === null
|
|
|
- ? pointJointLineDires[0] || pointJointLineDires[1]
|
|
|
- : pointJointLineDires[i];
|
|
|
- const isSplit = isSplitPoints[i];
|
|
|
- const joinLine = createLineByDire(joinDire, initPosition[i], 10);
|
|
|
-
|
|
|
- if (isSplit) {
|
|
|
- const addPointId = generateWholeLinePointId(config);
|
|
|
- config.points.push({
|
|
|
- ...pointAttribs[i],
|
|
|
- id: addPointId,
|
|
|
- });
|
|
|
- config.lines.forEach((line) => {
|
|
|
- if (line === lineAttrib) return;
|
|
|
- const ndx = line.pointIds.indexOf(pointAttribs[i].id);
|
|
|
- if (~ndx) {
|
|
|
- line.pointIds[ndx] = addPointId;
|
|
|
- }
|
|
|
- });
|
|
|
- console.log(wholeLineLineAddPoint(config, pointAttribs, addPointId));
|
|
|
+ // 将来回线段从多边形中剔除,额外建立多边形来存放
|
|
|
+ const delLines: WholeLinePointAttrib[][] = [];
|
|
|
+ for (let i = 0; i < config.polygons.length; i++) {
|
|
|
+ const polygon = config.polygons[i];
|
|
|
+
|
|
|
+ for (let j = 0; j < polygon.lineIds.length; j++) {
|
|
|
+ const current = getWholeLineLineRaw(config, polygon.lineIds[j]);
|
|
|
+ const nextNdx = (j + 1) % polygon.lineIds.length;
|
|
|
+ const next = getWholeLineLineRaw(config, polygon.lineIds[nextNdx]);
|
|
|
+
|
|
|
+ // 来回线段删除
|
|
|
+ if (
|
|
|
+ current.pointIds[0] === next.pointIds[1] &&
|
|
|
+ current.pointIds[1] === next.pointIds[0]
|
|
|
+ ) {
|
|
|
+ delLines.push(getWholeLinePoints(config, current.pointIds));
|
|
|
+ if (j > nextNdx) {
|
|
|
+ polygon.lineIds.splice(j, 1);
|
|
|
+ polygon.lineIds.splice(nextNdx, 1);
|
|
|
+ } else {
|
|
|
+ polygon.lineIds.splice(j, 2);
|
|
|
+ j -= 1;
|
|
|
+ }
|
|
|
+ wholeLineDelLineByPointIds(config, current.pointIds);
|
|
|
+ wholeLineDelLineByPointIds(config, next.pointIds);
|
|
|
+ continue;
|
|
|
+ // 小于一定阈值的也删除
|
|
|
}
|
|
|
|
|
|
- positions[i] = getLineProjection(joinLine, positions[i]).point;
|
|
|
+ const currentLine = getWholeLinePoints(config, current.pointIds);
|
|
|
+ if (
|
|
|
+ getLineDist(
|
|
|
+ [currentLine[0].x, currentLine[0].y],
|
|
|
+ [currentLine[1].x, currentLine[1].y]
|
|
|
+ ) < WHOLE_LINE_POINT_MERGE_DIST
|
|
|
+ ) {
|
|
|
+ wholeLineReplacePoint(config, [currentLine[0].id], currentLine[1].id);
|
|
|
+ j--;
|
|
|
+ }
|
|
|
+
|
|
|
+ // // 同向线段合并
|
|
|
+ // const currentLine = getWholeLinePoints(config, current.pointIds);
|
|
|
+ // const nextLine = getWholeLinePoints(config, current.pointIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (polygon.lineIds.length === 0) {
|
|
|
+ console.log("del polygon");
|
|
|
+ config.polygons.splice(i--, 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // console.log(positions);
|
|
|
- pointAttribs[0].x = positions[0][0];
|
|
|
- pointAttribs[0].y = positions[0][1];
|
|
|
- pointAttribs[1].x = positions[1][0];
|
|
|
- pointAttribs[1].y = positions[1][1];
|
|
|
+ delLines.forEach((pointAttribs) => {
|
|
|
+ if (pointAttribs[0].id === pointAttribs[1].id) return;
|
|
|
+ const id = generateWholeLinePoygonId(config);
|
|
|
+ const lineId = generateWholeLineLineId(config);
|
|
|
+
|
|
|
+ pointAttribs = pointAttribs.map((point) => {
|
|
|
+ if (config.points.some(({ id }) => id === point.id)) {
|
|
|
+ return point;
|
|
|
+ } else {
|
|
|
+ return wholeLineAddPoint(config, { x: point.x, y: point.y });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ config.lines.push({
|
|
|
+ id: lineId,
|
|
|
+ pointIds: pointAttribs.map(({ id }) => id),
|
|
|
+ });
|
|
|
+ console.log(lineId, id);
|
|
|
+ config.polygons.push({
|
|
|
+ id,
|
|
|
+ lineIds: [lineId],
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log(delLines);
|
|
|
};
|