123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- import {
- eqPoint,
- getLEJJoinNdxs,
- getLEJLineAngle,
- getLineEdgeJoinInfo,
- getLineEdges,
- LEJInfo,
- LEJLine,
- lineVector,
- Pos,
- verticalVector,
- } from "@/utils/math";
- import { LineData, LineDataLine } from ".";
- import { getJoinLine, getLinePoints } from "./attach-server";
- import { MathUtils } from "three";
- import { diffArrayChange, round } from "@/utils/shared";
- import { globalWatch, installGlobalVar } from "@/core/hook/use-global-vars";
- import { useStore } from "@/core/store";
- import { computed, nextTick, reactive, Ref, watch, watchEffect } from "vue";
- import { Transform } from "konva/lib/Util";
- import { sortFn } from "@/core/store/store";
- import { getLineIconEndpoints } from "../line-icon";
- import { useDrawIngData } from "@/core/hook/use-draw";
- import { polygonDifference, polygonDifferenceOnly } from "@/utils/math-clip";
- export const useGetExtendPolygon = (lineData: Ref<LineData | undefined>) => {
- const minAngle = MathUtils.degToRad(0.1);
- const palAngle = MathUtils.degToRad(20);
- type JInfo = { lej: LEJInfo | undefined; diffPolygons?: Pos[][] };
- const joinInfos = reactive({}) as Record<string, Record<string, JInfo>>;
- const getInfoKey = (line: LEJLine) =>
- line.points.reduce((t, p) => round(p.x, 3) + round(p.y, 3) + t, "") + line.width;
- const setLEJInfo = (
- data: LineData,
- originLine: LineDataLine,
- targetLine: LineDataLine
- ) => {
- const origin = {
- points: getLinePoints(data, originLine),
- width: originLine.strokeWidth,
- };
- const target = {
- points: getLinePoints(data, targetLine),
- width: targetLine.strokeWidth,
- };
- const { originNdx } = getLEJJoinNdxs(origin.points, target.points);
- const lej = getLineEdgeJoinInfo(origin, target, minAngle, palAngle);
- const originKey = getInfoKey(origin);
- if (!(originKey in joinInfos)) {
- joinInfos[originKey] = {};
- }
- if (!(originNdx in joinInfos[originKey])) {
- joinInfos[originKey][originNdx] = { lej };
- }
- return joinInfos[originKey][originNdx];
- };
- const getLEJPolygon = (data: LineData, originLine: LineDataLine) => {
- const origin = {
- points: getLinePoints(data, originLine),
- width: originLine.strokeWidth,
- };
- if (!origin.points[0] || !origin.points[1]) return [];
- const key = getInfoKey(origin);
- let originEdges: Pos[] = getLineEdges(origin.points, origin.width);
- const initOriginEdges = [...originEdges];
- const jInfos: (JInfo | undefined)[] = [
- joinInfos[key]?.[0],
- joinInfos[key]?.[1],
- ];
- if (!(key in joinInfos)) {
- return originEdges;
- }
- for (const info of jInfos) {
- if (!info?.lej) continue;
- for (const rep of info.lej) {
- const ndx = originEdges.indexOf(initOriginEdges[rep.rep]);
- originEdges.splice(ndx, 1, ...rep.points);
- }
- }
- for (const info of jInfos) {
- if (!info?.diffPolygons) continue;
- originEdges = polygonDifferenceOnly(originEdges, info.diffPolygons);
- }
- return originEdges;
- };
- const setManyJoinInfo = (data: LineData, lines: LineDataLine[]) => {
- type Select = ReturnType<typeof getLEJLineAngle> & {
- origin: LineDataLine;
- target: LineDataLine;
- };
- const selectLEJLines = (lines: LineDataLine[]) => {
- let select: Select;
- let maxAngle = -999;
- for (let i = 0; i < lines.length; i++) {
- const line1 = getLinePoints(data, lines[i]);
- for (let j = i + 1; j < lines.length; j++) {
- const line2 = getLinePoints(data, lines[j]);
- const ejlAngle = getLEJLineAngle(line1, line2);
- if (ejlAngle.norAngle > maxAngle) {
- maxAngle = ejlAngle.norAngle;
- select = {
- ...ejlAngle,
- origin: lines[i],
- target: lines[j],
- };
- }
- }
- }
- return select!;
- };
- let diffPolygons: Pos[][] = [];
- const pointIds = lines.flatMap(l => [l.a, l.b])
- const lineCount = lines.length
- while (lines.length) {
- if (lines.length > 1) {
- const select = selectLEJLines(lines)!;
- const origin = setLEJInfo(data, select.origin, select.target);
- const target = setLEJInfo(data, select.target, select.origin);
- lines = lines.filter(
- (line) => line !== select.origin && line !== select.target
- );
- origin.diffPolygons = diffPolygons
- target.diffPolygons = diffPolygons
- diffPolygons = [
- ...diffPolygons,
- getLEJPolygon(data, select.origin),
- getLEJPolygon(data, select.target),
- ];
- } else {
- const key = getInfoKey({
- points: getLinePoints(data, lines[0]),
- width: lines[0].strokeWidth,
- });
- if (!(key in joinInfos)) {
- joinInfos[key] = {};
- }
- const ndx = [lines[0].a, lines[0].b].findIndex(
- (id) => pointIds.filter(pid => id === pid).length === lineCount
- );
- joinInfos[key][ndx] = { lej: undefined, diffPolygons };
- lines = [];
- }
- }
- };
- const genLEJLine = (lineData: LineData, line: LineDataLine) => ({
- points: getLinePoints(lineData, line),
- width: line.strokeWidth,
- });
- const init = (data: LineData) => {
- const watchLine = (line: LineDataLine) => {
- const joina = computed(() => getJoinLine(data, line, line.a));
- const joinb = computed(() => getJoinLine(data, line, line.b));
- const self = computed(() => genLEJLine(data, line));
- const getWatchKey = () => {
- const lines = [
- ...joina.value.map((l) => genLEJLine(data, l)),
- ...joinb.value.map((l) => genLEJLine(data, l)),
- self.value,
- ];
- if (lines.some((l) => !l.points[0] || !l.points[1])) {
- return null;
- } else {
- return lines.map(getInfoKey).join(",");
- }
- };
- return watch(
- getWatchKey,
- (wkey, _2, onCleanup) => {
- if (!wkey) return;
- const key = getInfoKey(self.value);
- const calcNdxs: number[] = [];
- if (!(key in joinInfos)) {
- joinInfos[key] = {};
- calcNdxs.push(0, 1);
- } else {
- "0" in joinInfos[key] || calcNdxs.push(0);
- "1" in joinInfos[key] || calcNdxs.push(1);
- }
- for (const ndx of calcNdxs) {
- const joins = ndx === 0 ? joina.value : joinb.value;
- if (joins.length === 0) {
- joinInfos[key][ndx] = { lej: undefined };
- } else if (joins.length !== 1) {
- setManyJoinInfo(data, [line, ...joins]);
- } else {
- setLEJInfo(data, line, joins[0]);
- setLEJInfo(data, joins[0], line);
- }
- }
- onCleanup(() => {
- delete joinInfos[key];
- });
- },
- { immediate: true, flush: 'post' }
- );
- };
- let isStop = false;
- const stopMap = new WeakMap<LineDataLine, () => void>();
- const stopWatch = watch(
- () => [...data.lines],
- async (newLines, oldLines = []) => {
- const { added, deleted } = diffArrayChange(newLines, oldLines);
- deleted.forEach((line) => {
- const fn = stopMap.get(line);
- fn && fn();
- });
- await nextTick();
- if (!isStop) {
- added.forEach((line) => {
- stopMap.set(line, watchLine(line));
- });
- }
- deleted;
- },
- { immediate: true }
- );
- return () => {
- isStop = true;
- stopWatch();
- data.lines.forEach((line) => {
- const fn = stopMap.get(line);
- fn && fn();
- });
- };
- };
- watch(
- lineData,
- (data, _, onCleanup) => {
- data && onCleanup(init(data));
- },
- { immediate: true }
- );
- return (line: LineDataLine) => {
- const polygon = lineData.value ? getLEJPolygon(lineData.value, line) : [];
- 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 polygonDifference(polygon, targets);
- },
- onDestroy: stopWatch,
- };
- });
- // 计算与icon相差的多边形
- export const useGetDiffLineIconPolygons = (
- line: LineDataLine,
- 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
- ? polygonDifference(polygon, interPolygons.value)
- : [polygon];
- return result;
- },
- subSteps: subStepsLines,
- steps: stepLines,
- };
- };
|