|
@@ -19,16 +19,20 @@ import {
|
|
|
getVectorLine,
|
|
|
lineIntersection,
|
|
|
lineLen,
|
|
|
+ linePointLen,
|
|
|
linePointProjection,
|
|
|
lineVector,
|
|
|
Pos,
|
|
|
- vector,
|
|
|
vector2IncludedAngle,
|
|
|
verticalVector,
|
|
|
zeroEq,
|
|
|
} from "@/utils/math";
|
|
|
import { defaultStyle, getSnapInfos, type LineData } from "./";
|
|
|
-import { useCustomSnapInfos } from "@/core/hook/use-snap";
|
|
|
+import {
|
|
|
+ SnapResultInfo,
|
|
|
+ useCustomSnapInfos,
|
|
|
+ useSnapConfig,
|
|
|
+} from "@/core/hook/use-snap";
|
|
|
import { MathUtils, Vector2 } from "three";
|
|
|
import { getBaseItem } from "../util";
|
|
|
|
|
@@ -434,12 +438,14 @@ export const normalLineData = (data: LineData, ctx: NLineDataCtx) => {
|
|
|
export const genMoveLineHandler = (
|
|
|
data: LineData,
|
|
|
lineId: string,
|
|
|
+ snapConfig: ReturnType<typeof useSnapConfig>,
|
|
|
+ snapResult: SnapResultInfo,
|
|
|
ctx = getInitCtx()
|
|
|
) => {
|
|
|
const line = data.lines.find((line) => line.id === lineId)!;
|
|
|
const pointIds = [line.a, line.b];
|
|
|
const points = pointIds.map((id) => data.points.find((p) => p.id === id)!);
|
|
|
- const lineDire = lineVector(points)
|
|
|
+ const lineDire = lineVector(points);
|
|
|
const initPoints = copy(points);
|
|
|
const angleRange = [MathUtils.degToRad(10), MathUtils.degToRad(170)];
|
|
|
const getJoinLine = (pId: string) =>
|
|
@@ -462,6 +468,7 @@ export const genMoveLineHandler = (
|
|
|
const joinLineDires: Vector2[] = [];
|
|
|
const line = [points[ndx], points[Number(!ndx)]];
|
|
|
const lineDire = lineVector(line);
|
|
|
+ const joinPoints: LineData["points"] = [];
|
|
|
|
|
|
let invAngle = Number.MAX_VALUE;
|
|
|
let invSelectLineId: string;
|
|
@@ -472,6 +479,7 @@ export const genMoveLineHandler = (
|
|
|
let alongSelectLineDire: Vector2 | null = null;
|
|
|
|
|
|
for (const line of joinLines) {
|
|
|
+ joinPoints.push(...line.points.filter((p) => !points.includes(p)));
|
|
|
const joinDire = lineVector(line.points);
|
|
|
joinLineDires.push(joinDire);
|
|
|
|
|
@@ -530,16 +538,19 @@ export const genMoveLineHandler = (
|
|
|
rangMod(vector2IncludedAngle(dire, info.selectLineDire), Math.PI)
|
|
|
)
|
|
|
);
|
|
|
- return { ...info, needSplit, needVertical };
|
|
|
+ return { ...info, needSplit, needVertical, joinPoints };
|
|
|
};
|
|
|
|
|
|
let refInfos: ReturnType<typeof getRefInfo>[];
|
|
|
let snapLines: (null | Pos[])[];
|
|
|
let inited = false;
|
|
|
+ let norNdx = -1;
|
|
|
|
|
|
const init = (moveDires: Vector2[]) => {
|
|
|
refInfos = [getRefInfo(moveDires[0], 0), getRefInfo(moveDires[0], 1)];
|
|
|
snapLines = [];
|
|
|
+ let minAngle = Math.PI / 2;
|
|
|
+ const vLineDire = verticalVector(lineDire);
|
|
|
for (let i = 0; i < refInfos.length; i++) {
|
|
|
const refInfo = refInfos[i];
|
|
|
if (!refInfo) {
|
|
@@ -570,16 +581,38 @@ export const genMoveLineHandler = (
|
|
|
const dire = refInfo.needVertical
|
|
|
? verticalVector(refInfo.selectLineDire)
|
|
|
: refInfo.selectLineDire;
|
|
|
+
|
|
|
+ const angle = rangMod(vector2IncludedAngle(dire, vLineDire), Math.PI / 2);
|
|
|
+ if (angle < minAngle) {
|
|
|
+ norNdx = i;
|
|
|
+ minAngle = angle;
|
|
|
+ }
|
|
|
snapLines[i] = getVectorLine(dire, copy(points[i]), 10);
|
|
|
}
|
|
|
};
|
|
|
- const assignPos = (origin: LineData['points'][0], target: Pos) => {
|
|
|
- origin.x = target.x
|
|
|
- origin.y = target.y
|
|
|
- ctx.update.points[origin.id] = origin
|
|
|
- }
|
|
|
+ const assignPos = (origin: LineData["points"][0], target: Pos) => {
|
|
|
+ origin.x = target.x;
|
|
|
+ origin.y = target.y;
|
|
|
+ ctx.update.points[origin.id] = origin;
|
|
|
+ };
|
|
|
|
|
|
- const handler = (finalPoss: Pos[]) => {
|
|
|
+ const updateOtPoint = (ndx: number) => {
|
|
|
+ const uNdx = ndx === 1 ? 0 : 1;
|
|
|
+ const move = new Vector2(
|
|
|
+ points[ndx].x - initPoints[ndx].x,
|
|
|
+ points[ndx].y - initPoints[ndx].y
|
|
|
+ );
|
|
|
+ if (!snapLines[uNdx]) {
|
|
|
+ assignPos(points[uNdx], move.add(initPoints[uNdx]));
|
|
|
+ } else {
|
|
|
+ assignPos(
|
|
|
+ points[uNdx],
|
|
|
+ lineIntersection(getVectorLine(lineDire, points[ndx]), snapLines[uNdx])!
|
|
|
+ );
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const move = (finalPoss: Pos[]) => {
|
|
|
if (!inited) {
|
|
|
const moveDires = finalPoss.map((pos, ndx) =>
|
|
|
lineVector([initPoints[ndx], pos])
|
|
@@ -589,33 +622,88 @@ export const genMoveLineHandler = (
|
|
|
}
|
|
|
|
|
|
if (!snapLines[0] && !snapLines[1]) {
|
|
|
- assignPos(points[0], finalPoss[0])
|
|
|
- assignPos(points[1], finalPoss[1])
|
|
|
- return;
|
|
|
+ assignPos(points[0], finalPoss[0]);
|
|
|
+ assignPos(points[1], finalPoss[1]);
|
|
|
} else if (!snapLines[0]) {
|
|
|
- const pos = linePointProjection(snapLines[1]!, finalPoss[1])
|
|
|
- assignPos(points[1], pos)
|
|
|
- assignPos(points[0], pos.sub(initPoints[1]).add(initPoints[0]))
|
|
|
- return;
|
|
|
+ const pos = linePointProjection(snapLines[1]!, finalPoss[1]);
|
|
|
+ assignPos(points[1], pos);
|
|
|
+ updateOtPoint(1);
|
|
|
} else if (!snapLines[1]) {
|
|
|
- const pos = linePointProjection(snapLines[0]!, finalPoss[0])
|
|
|
- assignPos(points[0], pos)
|
|
|
- assignPos(points[1], pos.sub(initPoints[0]).add(initPoints[1]))
|
|
|
- return;
|
|
|
+ const pos = linePointProjection(snapLines[0]!, finalPoss[0]);
|
|
|
+ assignPos(points[0], pos);
|
|
|
+ updateOtPoint(0);
|
|
|
+ } else {
|
|
|
+ const pos = linePointProjection(snapLines[norNdx]!, finalPoss[norNdx]);
|
|
|
+ assignPos(points[norNdx], pos);
|
|
|
+ updateOtPoint(norNdx);
|
|
|
}
|
|
|
+ };
|
|
|
|
|
|
- const moves = snapLines.map((snapLine, i) => {
|
|
|
- const pos = !snapLine ? finalPoss[i] : linePointProjection(snapLine, finalPoss[i])
|
|
|
- return vector(pos).sub(initPoints[i])
|
|
|
- });
|
|
|
- if (moves[0].lengthSq() > moves[1].lengthSq()) {
|
|
|
- assignPos(points[0], moves[0].add(initPoints[0]));
|
|
|
- assignPos(points[1], lineIntersection(getVectorLine(lineDire, points[0]), snapLines[1])!)
|
|
|
- } else {
|
|
|
- assignPos(points[1], moves[1].add(initPoints[1]));
|
|
|
- assignPos(points[0], lineIntersection(getVectorLine(lineDire, points[1]), snapLines[0])!)
|
|
|
+ const getSnapRefPoint = (point: Pos, refPoints: Pos[], line: Pos[] | null) => {
|
|
|
+ for (const refPoint of refPoints) {
|
|
|
+ if (
|
|
|
+ lineLen(refPoint, point) < snapConfig.snapOffset &&
|
|
|
+ (!line || zeroEq(linePointLen(line, refPoint)))
|
|
|
+ ) {
|
|
|
+ return refPoint;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const snap = () => {
|
|
|
+ snapResult.clear();
|
|
|
+ let refPoint: Pos | undefined = undefined;
|
|
|
+ let ndx = -1;
|
|
|
+
|
|
|
+ const useRefPoint = () => {
|
|
|
+ const hv = [
|
|
|
+ { join: refPoint, refDirection: { x: 0, y: 1 } },
|
|
|
+ { join: refPoint, refDirection: { x: 1, y: 0 } },
|
|
|
+ ];
|
|
|
+ snapResult.attractSnaps.push(...(hv as any));
|
|
|
+ assignPos(points[ndx], refPoint!);
|
|
|
+ updateOtPoint(ndx);
|
|
|
+ };
|
|
|
+
|
|
|
+ if (refInfos[0]?.joinPoints) {
|
|
|
+ refPoint = getSnapRefPoint(points[0], refInfos[0]?.joinPoints, snapLines[0]);
|
|
|
+ if (refPoint) {
|
|
|
+ ndx = 0;
|
|
|
+ return useRefPoint();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (refInfos[1]?.joinPoints) {
|
|
|
+ refPoint = getSnapRefPoint(points[1], refInfos[1]?.joinPoints, snapLines[1]);
|
|
|
+ if (refPoint) {
|
|
|
+ ndx = 1;
|
|
|
+ return useRefPoint();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const usedPoints = [
|
|
|
+ ...(refInfos[0]?.joinPoints || []),
|
|
|
+ ...(refInfos[1]?.joinPoints || []),
|
|
|
+ ...points,
|
|
|
+ ];
|
|
|
+ const refPoints = data.points.filter((p) => !usedPoints.includes(p));
|
|
|
+ for (let i = 0; i < points.length; i++) {
|
|
|
+ refPoint = getSnapRefPoint(points[i], refPoints, snapLines[i]);
|
|
|
+ if (refPoint) {
|
|
|
+ ndx = i;
|
|
|
+ return useRefPoint();
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- return handler;
|
|
|
+ const end = () => {
|
|
|
+ snapResult.clear();
|
|
|
+ };
|
|
|
+
|
|
|
+ return {
|
|
|
+ move: (ps: Pos[]) => {
|
|
|
+ move(ps);
|
|
|
+ snap();
|
|
|
+ },
|
|
|
+ end,
|
|
|
+ };
|
|
|
};
|