123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- import {
- eqPoint,
- getDiffPolygons,
- getVectorLine,
- isPolygonPointInner,
- lineCenter,
- lineInner,
- lineIntersection,
- lineLen,
- lineVector,
- lineVerticalVector,
- Pos,
- vector2IncludedAngle,
- verticalVector,
- } from "@/utils/math";
- import { LineData } from ".";
- import { getJoinLine } from "./attach-server";
- import { MathUtils } from "three";
- import { diffArrayChange, rangMod } from "@/utils/shared";
- import { globalWatch, installGlobalVar } from "@/core/hook/use-global-vars";
- import { useStore } from "@/core/store";
- import { computed, reactive, Ref, toRaw, watchEffect } from "vue";
- import { Transform } from "konva/lib/Util";
- import { sortFn } from "@/core/store/store";
- import { getLineIconEndpoints, getSnapLine } from "../line-icon";
- import { useDrawIngData } from "@/core/hook/use-draw";
- import { useTestPoints } from "@/core/hook/use-debugger";
- const minAngle = MathUtils.degToRad(0.1);
- const palAngle = MathUtils.degToRad(20);
- const getLineRect = (points: Pos[], strokeWidth: number) => {
- const v = lineVector(points);
- const vv = verticalVector(v);
- const offset = vv.clone().multiplyScalar(strokeWidth / 2);
- const top = points.map((p) => offset.clone().add(p));
- offset.multiplyScalar(-1);
- const bottom = points.map((p) => offset.clone().add(p));
- return [...top, bottom[1], bottom[0]];
- };
- export const useGetExtendPolygon = installGlobalVar(() => {
- return (data: LineData, line: LineData["lines"][0], useJoin = true) => {
- const getJoinInfo = (
- joinLine: LineData["lines"][0],
- joinPoints: Pos[],
- getNdx: number
- ) => {
- const jNdx = joinPoints.indexOf(linePoints[getNdx]);
- if ((getNdx === 0 && jNdx === 0) || (getNdx === 1 && jNdx === 1)) {
- joinPoints.reverse();
- }
- const direInv = getNdx === 0 && jNdx === 0;
- const joinv = lineVector(joinPoints).multiplyScalar(-1);
- const angle = vector2IncludedAngle(
- direInv ? joinv : linev,
- direInv ? linev : joinv
- );
- const checkAngle = rangMod(Math.abs(angle), Math.PI);
- if (checkAngle < minAngle || checkAngle > Math.PI - minAngle) return;
- const join = lineIntersection(linePoints, joinPoints);
- if (!join) return;
- const center = lineCenter([...linePoints, ...joinPoints]);
- const joinRect = getLineRect(joinPoints, joinLine.strokeWidth);
- const cheJoinInnerNdxs = getNdx === 0 ? [0, 3] : [1, 2];
- const cheLineInnerNdxs = getNdx === 0 ? [1, 2] : [0, 3];
- if (
- cheJoinInnerNdxs.some((ndx) =>
- isPolygonPointInner(lineRect, joinRect[ndx])
- ) ||
- cheLineInnerNdxs.some((ndx) =>
- isPolygonPointInner(joinRect, lineRect[ndx])
- )
- ) {
- return;
- }
- let outerLine1, innerLine1, outerLine2, innerLine2;
- const rectJust =
- lineLen(center, lineRect[0]) > lineLen(center, lineRect[3]);
- if (rectJust) {
- outerLine1 = [lineRect[0], lineRect[1]];
- innerLine1 = [lineRect[3], lineRect[2]];
- } else {
- outerLine1 = [lineRect[3], lineRect[2]];
- innerLine1 = [lineRect[0], lineRect[1]];
- }
- if (lineLen(center, joinRect[0]) > lineLen(center, joinRect[3])) {
- outerLine2 = [joinRect[0], joinRect[1]];
- innerLine2 = [joinRect[3], joinRect[2]];
- } else {
- outerLine2 = [joinRect[3], joinRect[2]];
- innerLine2 = [joinRect[0], joinRect[1]];
- }
- const outer = lineIntersection(outerLine1, outerLine2);
- if (!outer) return;
- let inside: Pos = lineIntersection(innerLine1, innerLine2)!;
- if (!inside) return;
- const insideLineInner1 = lineInner(innerLine1, inside);
- const insideLineInner2 = lineInner(innerLine2, inside);
- if (!insideLineInner1 && !insideLineInner2) return;
- let insides = [inside];
- // 如果角度过于尖锐则使用平行线
- let outers = [outer];
- if (checkAngle < palAngle) {
- const jov = getVectorLine(lineVerticalVector([join, outer]), join);
- const outer1 = lineIntersection(jov, outerLine1)!;
- outers = [outer1, join];
- }
- const repsResult: { rep: number; points: Pos[] }[] = [];
- if (getNdx === 0) {
- repsResult.push({
- rep: 0,
- points: rectJust ? outers.reverse() : insides,
- });
- repsResult.push({ rep: 3, points: rectJust ? insides : outers });
- } else {
- repsResult.push({ rep: 1, points: rectJust ? outers : insides });
- repsResult.push({
- rep: 2,
- points: rectJust ? insides : outers.reverse(),
- });
- }
- // testPoints.value.push(...insides, ...outers);
- return repsResult;
- };
- const linePoints = [line.a, line.b].map(
- (id) => data.points.find((item) => item.id === id)!
- );
- const lineRect: Pos[] = getLineRect(linePoints, line.strokeWidth);
- const polygon = [...lineRect];
- const linev = lineVector(linePoints);
- if (!useJoin) {
- return polygon;
- }
- linePoints.forEach((point, ndx) => {
- const joinLines = getJoinLine(data, line, point.id);
- if (joinLines.length !== 1) return;
- const repsResult = getJoinInfo(joinLines[0], joinLines[0].points, ndx);
- if (!repsResult) return;
- for (const rep of repsResult) {
- const ndx = polygon.indexOf(lineRect[rep.rep]);
- polygon.splice(ndx, 1, ...rep.points);
- }
- });
- return polygon;
- };
- });
- // 计算与icon相差的多边形
- export const useGetDiffIconPolygons = installGlobalVar(() => {
- const store = useStore();
- const iconPolygons = reactive({}) as { [key in string]: Pos[] };
- const icons = computed(() => store.getTypeItems("icon"));
- const line = computed(() => store.getTypeItems("line")[0]);
- const watchIcon = (id: string) => {
- const stopWatch = watchEffect(() => {
- const icon = icons.value.find((item) => item.id === id);
- if (!icon) {
- stopWatch();
- delete iconPolygons[id];
- return;
- }
- if (!line.value || sortFn(line.value, icon) > 0) {
- delete iconPolygons[id];
- return;
- }
- const rect = [
- { x: -icon.width / 2, y: -icon.height / 2 },
- { x: icon.width / 2, y: -icon.height / 2 },
- { x: icon.width / 2, y: icon.height / 2 },
- { x: -icon.width / 2, y: icon.height / 2 },
- ];
- const mat = new Transform(icon.mat);
- iconPolygons[id] = rect.map((p) => mat.point(p));
- });
- };
- const stopWatch = globalWatch(
- () => {
- return icons.value.map((item) => item.id);
- },
- (ids, oIds = []) => {
- const { added, deleted } = diffArrayChange(ids, oIds);
- deleted.forEach((id) => {
- delete iconPolygons[id];
- });
- added.forEach(watchIcon);
- },
- { immediate: true }
- );
- return {
- var: (polygon: Pos[]) => {
- const targets = Object.values(iconPolygons);
- if (!targets.length) return [polygon];
- return getDiffPolygons(polygon, targets);
- },
- onDestroy: stopWatch,
- };
- });
- // 计算与icon相差的多边形
- export const useGetDiffLineIconPolygons = (line: LineData["lines"][0], linePoints: Ref<Pos[]>) => {
- const store = useStore();
- const drawStore = useDrawIngData();
- const linevv = computed(() => verticalVector(lineVector(linePoints.value!)));
- const icons = computed(() => {
- const icons = store
- .getTypeItems("lineIcon")
- .concat(drawStore.lineIcon || []);
- return icons.filter((item) => !item.hide);
- });
- const lineIcons = computed(() =>
- icons.value.filter((icon) => icon.lineId === line.id)
- );
- const interSteps = computed(() => {
- const lineSteps = lineIcons.value
- .map((icon) => {
- const openSide = icon.openSide;
- const endLen = icon.endLen || 0.001;
- const startLen = icon.startLen || 0.001;
- const inv = endLen < startLen;
- return {
- lens: inv ? [endLen, startLen] : [startLen, endLen],
- openSide: inv ? (openSide === "LEFT" ? "RIGHT" : "LEFT") : openSide,
- };
- })
- .sort((line1, line2) => line1.lens[0] - line2.lens[0]);
- if (!lineSteps.length) return [];
- const interSteps: { lens: number[]; openSide: "LEFT" | "RIGHT" }[] = [];
- let i = 0;
- do {
- const startStep = lineSteps[i].lens[0];
- const openSide = lineSteps[i].openSide;
- let endStep = lineSteps[i].lens[1];
- for (i++; i < lineSteps.length; i++) {
- if (lineSteps[i].lens[0] <= endStep) {
- if (lineSteps[i].lens[1] > endStep) {
- endStep = lineSteps[i].lens[1];
- }
- } else {
- break;
- }
- }
- interSteps.push({
- lens: [startStep, endStep],
- openSide,
- });
- } while (i < lineSteps.length);
- return interSteps;
- });
- const interLines = computed(() =>
- interSteps.value.map((steps) => ({
- openSide: steps.openSide,
- points: getLineIconEndpoints(linePoints.value!, {
- startLen: steps.lens[0],
- endLen: steps.lens[1],
- }),
- }))
- );
- const stepLines = computed(() => {
- if (!linePoints.value?.length || !interLines.value.length) return [];
- const steps: Pos[][] = [];
- if (!eqPoint(linePoints.value[0], interLines.value[0].points[0])) {
- steps.push([linePoints.value[0], interLines.value[0].points[0]]);
- }
- let start = interLines.value[0].points[1];
- let i = 1;
- for (; i < interLines.value.length; i++) {
- const iLine = interLines.value[i];
- steps.push([start, iLine.points[0]]);
- start = iLine.points[1];
- }
- if (!eqPoint(start, linePoints.value[1])) {
- steps.push([start, linePoints.value[1]]);
- }
- return steps;
- });
- const subStepsLines = computed(() => {
- return interLines.value.map((il) => {
- return il.openSide === "RIGHT" ? il.points : [...il.points].reverse();
- });
- });
- const interPolygons = computed(() => {
- return interLines.value.map((il) => {
- const interLine = il.points;
- const topOffset = linevv.value.clone().multiplyScalar(line.strokeWidth);
- const botOffset = topOffset.clone().multiplyScalar(-1);
- return [
- topOffset.clone().add(interLine[0]),
- topOffset.clone().add(interLine[1]),
- botOffset.clone().add(interLine[1]),
- botOffset.clone().add(interLine[0]),
- ];
- });
- });
- return {
- diff: (polygon: Pos[]) => {
- const result = interPolygons.value.length
- ? getDiffPolygons(polygon, interPolygons.value)
- : [polygon];
- return result;
- },
- subSteps: subStepsLines,
- steps: stepLines,
- };
- };
|