|
@@ -0,0 +1,453 @@
|
|
|
+import {
|
|
|
+ WholeLineAttrib,
|
|
|
+ WholeLineLineAttrib,
|
|
|
+ WholeLinePointAttrib,
|
|
|
+ WholeLinePolygonAttrib,
|
|
|
+} from "../view";
|
|
|
+
|
|
|
+export const generateWholeLineLineId = (config: WholeLineAttrib) =>
|
|
|
+ (Math.max(...config.lines.map(({ id }) => Number(id))) + 1).toString();
|
|
|
+
|
|
|
+export const generateWholeLinePointId = (config: WholeLineAttrib) =>
|
|
|
+ (Math.max(...config.points.map(({ id }) => Number(id))) + 1).toString();
|
|
|
+
|
|
|
+export const getWholeLinePoint = (config: WholeLineAttrib, id: string) =>
|
|
|
+ config.points.find((point) => point.id === id);
|
|
|
+
|
|
|
+export const getWholeLinePoints = (config: WholeLineAttrib, ids?: string[]) => {
|
|
|
+ if (ids) {
|
|
|
+ return ids.map((id) => getWholeLinePoint(config, id));
|
|
|
+ } else {
|
|
|
+ return config.points;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+export const getWholeLineLineRaw = (config: WholeLineAttrib, lineId: string) =>
|
|
|
+ config.lines.find(({ id }) => id === lineId);
|
|
|
+
|
|
|
+export const getWholeLineLinesRaw = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ lineIds: string[]
|
|
|
+) => lineIds.map((lineId) => getWholeLineLineRaw(config, lineId));
|
|
|
+
|
|
|
+export const getWholeLineLine = (config: WholeLineAttrib, lineId: string) =>
|
|
|
+ getWholeLinePoints(config, getWholeLineLineRaw(config, lineId).pointIds);
|
|
|
+
|
|
|
+export const getWholeLineLines = (config: WholeLineAttrib) => {
|
|
|
+ return config.lines.map((p) => getWholeLinePoints(config, p.pointIds));
|
|
|
+};
|
|
|
+
|
|
|
+// getWholeLinePolygon
|
|
|
+export const getWholeLinePolygonRaw = (config: WholeLineAttrib, id: string) => {
|
|
|
+ return config.polygons.find((p) => p.id === id);
|
|
|
+};
|
|
|
+
|
|
|
+export const getWholeLinePolygonLines = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ polygonId: string
|
|
|
+) => {
|
|
|
+ return getWholeLinePolygonRaw(config, polygonId).lineIds.map((lineId) =>
|
|
|
+ getWholeLineLine(config, lineId)
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export const getWholeLinePolygonLinesRaw = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ polygonId: string
|
|
|
+) => {
|
|
|
+ return getWholeLinePolygonRaw(config, polygonId).lineIds.map((lineId) =>
|
|
|
+ getWholeLineLineRaw(config, lineId)
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+// getWholeLineLinesByPoint
|
|
|
+export const getWholeLineLinesByPointId = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ pointId: string
|
|
|
+) =>
|
|
|
+ config.lines
|
|
|
+ .filter(({ pointIds }) => pointIds.includes(pointId))
|
|
|
+ .map((line) => getWholeLineLine(config, line.id));
|
|
|
+
|
|
|
+// getWholeLinePolygonLinesByPoint
|
|
|
+export const getWholeLinePolygonLinesByPoint = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ pointId: string
|
|
|
+) => {
|
|
|
+ const pLines: { polygonId: string; lines: WholeLinePointAttrib[][] }[] = [];
|
|
|
+ for (const polygon of config.polygons) {
|
|
|
+ const lines = polygon.lineIds
|
|
|
+ .filter((lId) =>
|
|
|
+ getWholeLineLineRaw(config, lId).pointIds.includes(pointId)
|
|
|
+ )
|
|
|
+ .map((lineId) => getWholeLineLine(config, lineId));
|
|
|
+
|
|
|
+ if (lines.length) {
|
|
|
+ pLines.push({
|
|
|
+ polygonId: polygon.id,
|
|
|
+ lines,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return pLines;
|
|
|
+};
|
|
|
+
|
|
|
+export const getWholeLinePolygonPoints = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ polygonId: string
|
|
|
+) => {
|
|
|
+ const { lineIds } = getWholeLinePolygonRaw(config, polygonId);
|
|
|
+ const points: WholeLinePointAttrib[] = [];
|
|
|
+ for (let i = 0; i < lineIds.length; i++) {
|
|
|
+ const lineRaw = getWholeLineLineRaw(config, lineIds[i]);
|
|
|
+ points.push(getWholeLinePoint(config, lineRaw.pointIds[0]));
|
|
|
+ if (i === lineIds.length - 1) {
|
|
|
+ points.push(getWholeLinePoint(config, lineRaw.pointIds[1]));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return points;
|
|
|
+};
|
|
|
+
|
|
|
+export type WholeLineChange = {
|
|
|
+ lineChange?: {
|
|
|
+ del?: WholeLineLineAttrib[];
|
|
|
+ update?: { before: WholeLineLineAttrib[]; after: WholeLineLineAttrib[] }[];
|
|
|
+ add?: WholeLineLineAttrib[];
|
|
|
+ };
|
|
|
+ polygonChange?: {
|
|
|
+ add?: WholeLinePolygonAttrib[];
|
|
|
+ update?: {
|
|
|
+ before: WholeLinePolygonAttrib;
|
|
|
+ after: WholeLinePolygonAttrib;
|
|
|
+ }[];
|
|
|
+ del?: WholeLinePolygonAttrib[];
|
|
|
+ };
|
|
|
+ pointChange?: {
|
|
|
+ add?: WholeLinePointAttrib[];
|
|
|
+ del?: WholeLinePointAttrib[];
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+export const getWholeLineLineNdxByPointIds = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ qPointIds: string[]
|
|
|
+) =>
|
|
|
+ config.lines.findIndex(
|
|
|
+ ({ pointIds }) =>
|
|
|
+ pointIds[0] === qPointIds[0] && pointIds[1] === qPointIds[1]
|
|
|
+ );
|
|
|
+
|
|
|
+/**
|
|
|
+ * 添加线段,只有config.lines不存在时会添加
|
|
|
+ * @param config WholeLine
|
|
|
+ * @param addPointIds 线段点id[]
|
|
|
+ * @returns 变化
|
|
|
+ */
|
|
|
+export const wholeLineAddLineByPointIds = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ addPointIds: string[]
|
|
|
+) => {
|
|
|
+ const change: WholeLineChange = {
|
|
|
+ lineChange: { add: [] },
|
|
|
+ };
|
|
|
+ let eLineNdx = getWholeLineLineNdxByPointIds(config, addPointIds);
|
|
|
+ if (!~eLineNdx) {
|
|
|
+ eLineNdx =
|
|
|
+ config.lines.push({
|
|
|
+ id: generateWholeLineLineId(config),
|
|
|
+ pointIds: [...addPointIds],
|
|
|
+ }) - 1;
|
|
|
+ change.lineChange.add.push(config.lines[eLineNdx]);
|
|
|
+ }
|
|
|
+ return { line: config.lines[eLineNdx], change };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 删除线段,只有polygon没有引用时会删除
|
|
|
+ * @param config WholeLine
|
|
|
+ * @param delPointIds 线段点id[]
|
|
|
+ * @returns 变化
|
|
|
+ */
|
|
|
+export const wholeLineDelLineByPointIds = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ delPointIds: string[]
|
|
|
+) => {
|
|
|
+ const change: WholeLineChange = {
|
|
|
+ lineChange: { del: [] },
|
|
|
+ pointChange: { del: [] },
|
|
|
+ };
|
|
|
+ const eLineNdx = getWholeLineLineNdxByPointIds(config, delPointIds);
|
|
|
+ const eLineRaw = config.lines[eLineNdx];
|
|
|
+ if (!~eLineNdx) {
|
|
|
+ return { change };
|
|
|
+ }
|
|
|
+ let canDel = config.polygons.every(
|
|
|
+ ({ lineIds }) => !lineIds.includes(eLineRaw.id)
|
|
|
+ );
|
|
|
+ if (canDel) {
|
|
|
+ config.lines.splice(eLineNdx, 1);
|
|
|
+ change.lineChange.del.push(eLineRaw);
|
|
|
+ }
|
|
|
+
|
|
|
+ delPointIds.forEach((delPointId) => {
|
|
|
+ const ndx = config.points.findIndex(({ id }) => id === delPointId);
|
|
|
+ if (
|
|
|
+ ~ndx &&
|
|
|
+ config.lines.every(({ pointIds }) => !pointIds.includes(delPointId))
|
|
|
+ ) {
|
|
|
+ change.pointChange.del.push(config.points[ndx]);
|
|
|
+ config.points.splice(ndx, 1);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return { line: eLineRaw, change };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 删除点,会影响polygons 和lines points
|
|
|
+ * @param config WholeLine
|
|
|
+ * @param delPointIds 要删除的点ids
|
|
|
+ * @returns 变化
|
|
|
+ */
|
|
|
+export const wholeLineDelPointByPointIds = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ delPointIds: string[]
|
|
|
+) => {
|
|
|
+ const change: WholeLineChange = {
|
|
|
+ lineChange: {
|
|
|
+ del: [],
|
|
|
+ add: [],
|
|
|
+ },
|
|
|
+ polygonChange: {
|
|
|
+ update: [],
|
|
|
+ del: [],
|
|
|
+ },
|
|
|
+ pointChange: {
|
|
|
+ del: [],
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ for (let i = 0; i < config.polygons.length; i++) {
|
|
|
+ const polygon = config.polygons[i];
|
|
|
+ const lineIds = polygon.lineIds;
|
|
|
+ const lines = getWholeLineLinesRaw(config, lineIds);
|
|
|
+ let initPolygonLineIds: string[];
|
|
|
+
|
|
|
+ for (let ndx = 0; ndx < lines.length; ndx++) {
|
|
|
+ const lineRaw = lines[ndx];
|
|
|
+ const prev = delPointIds.includes(lineRaw.pointIds[0]);
|
|
|
+ const last = delPointIds.includes(lineRaw.pointIds[1]);
|
|
|
+ if (!(prev || last)) continue;
|
|
|
+ initPolygonLineIds = initPolygonLineIds || [...lineIds];
|
|
|
+
|
|
|
+ // [1,2][2,3][3,4]
|
|
|
+ // delp 2, 3 delL [2, 3] [3, 4] updateL [1, 2] -> [1, 4]
|
|
|
+ // delp 1, 3 delL [1, 2] [3, 4] updateL [2, 3] -> [2, 4]
|
|
|
+ // delp 4 delL [3, 4]
|
|
|
+ // delp 1 delL [1, 2]
|
|
|
+ // delp 3 delL [3, 4] updateL [2, 3] -> [2, 4]
|
|
|
+
|
|
|
+ let delNdx = ndx;
|
|
|
+ if (last) {
|
|
|
+ // delp 3, 4 delL [2, 3][3, 4]
|
|
|
+ // 特殊情况
|
|
|
+ let nextNdx = ndx + 1;
|
|
|
+ for (nextNdx; nextNdx < lines.length; nextNdx++) {
|
|
|
+ const nextPId = lines[nextNdx].pointIds[1];
|
|
|
+ if (
|
|
|
+ !delPointIds.includes(nextPId) &&
|
|
|
+ nextPId !== lineRaw.pointIds[0]
|
|
|
+ ) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (nextNdx !== lines.length) {
|
|
|
+ const adL = wholeLineAddLineByPointIds(config, [
|
|
|
+ lineRaw.pointIds[0],
|
|
|
+ lines[nextNdx].pointIds[1],
|
|
|
+ ]);
|
|
|
+ change.lineChange.add.push(...adL.change.lineChange.add);
|
|
|
+ lineIds[ndx] = adL.line.id;
|
|
|
+ delNdx = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (~delNdx) {
|
|
|
+ const delPointIds = lines[ndx].pointIds;
|
|
|
+ lineIds.splice(ndx--, 1);
|
|
|
+
|
|
|
+ const dL = wholeLineDelLineByPointIds(config, delPointIds);
|
|
|
+ change.lineChange.del.push(...dL.change.lineChange.del);
|
|
|
+ change.pointChange.del.push(...dL.change.pointChange.del);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (initPolygonLineIds) {
|
|
|
+ const beforePolygon = { ...polygon, lineIds: initPolygonLineIds };
|
|
|
+ if (polygon.lineIds.length === 0) {
|
|
|
+ config.polygons.splice(i--, 1);
|
|
|
+ change.polygonChange.del.push(beforePolygon);
|
|
|
+ } else {
|
|
|
+ change.polygonChange.update.push({
|
|
|
+ before: beforePolygon,
|
|
|
+ after: polygon,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return change;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 线段加点
|
|
|
+ * @param config
|
|
|
+ * @param polygonLine
|
|
|
+ * @param addPoint
|
|
|
+ * @param effectLines 要修改对应影响的线
|
|
|
+ */
|
|
|
+// wholeLinePolygonLineAddPoint
|
|
|
+export const wholeLineLineAddPoint = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ line: WholeLinePointAttrib[],
|
|
|
+ pointId: string
|
|
|
+) => {
|
|
|
+ const change: WholeLineChange = {
|
|
|
+ lineChange: {
|
|
|
+ del: [],
|
|
|
+ add: [],
|
|
|
+ },
|
|
|
+ polygonChange: {
|
|
|
+ update: [],
|
|
|
+ },
|
|
|
+ pointChange: {
|
|
|
+ add: [],
|
|
|
+ del: [],
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ let addedPoints: string[] | null = null;
|
|
|
+ const lineIds = line.map((p) => p.id);
|
|
|
+ if (lineIds.includes(pointId)) {
|
|
|
+ return { addedPoints, change };
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const polygon of config.polygons) {
|
|
|
+ let initPolygonLineIds: string[];
|
|
|
+ for (let ndx = 0; ndx < polygon.lineIds.length; ndx++) {
|
|
|
+ const lineRaw = getWholeLineLineRaw(config, polygon.lineIds[ndx]);
|
|
|
+ // 如果需要添加的点已经是线段的起点或终点则直接忽略
|
|
|
+ if (
|
|
|
+ lineIds.includes(lineRaw.pointIds[0]) &&
|
|
|
+ lineIds.includes(lineRaw.pointIds[1])
|
|
|
+ ) {
|
|
|
+ initPolygonLineIds = initPolygonLineIds || [...polygon.lineIds];
|
|
|
+ addedPoints = addedPoints || [
|
|
|
+ lineRaw.pointIds[0],
|
|
|
+ pointId,
|
|
|
+ lineRaw.pointIds[1],
|
|
|
+ ];
|
|
|
+ const addl1 = wholeLineAddLineByPointIds(config, [
|
|
|
+ lineRaw.pointIds[0],
|
|
|
+ pointId,
|
|
|
+ ]);
|
|
|
+ // [1,2][2,3] [2,4, 3]
|
|
|
+ // [1.2][2.4],[4.3]
|
|
|
+ const addl2 = wholeLineAddLineByPointIds(config, [
|
|
|
+ pointId,
|
|
|
+ lineRaw.pointIds[1],
|
|
|
+ ]);
|
|
|
+
|
|
|
+ change.lineChange.add.push(
|
|
|
+ ...addl1.change.lineChange.add,
|
|
|
+ ...addl2.change.lineChange.add
|
|
|
+ );
|
|
|
+ polygon.lineIds.splice(ndx, 1, addl1.line.id, addl2.line.id);
|
|
|
+
|
|
|
+ const dl = wholeLineDelLineByPointIds(config, lineRaw.pointIds);
|
|
|
+ change.lineChange.del.push(...dl.change.lineChange.del);
|
|
|
+ change.pointChange.del.push(...dl.change.pointChange.del);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (initPolygonLineIds) {
|
|
|
+ change.polygonChange.update.push({
|
|
|
+ before: { ...polygon, lineIds: initPolygonLineIds },
|
|
|
+ after: polygon,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return { addedPoints, change };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 替换点
|
|
|
+ * @param config WholeLine
|
|
|
+ * @param originPointIds 原有点集合
|
|
|
+ * @param replacePointId 最要点id
|
|
|
+ * @returns 变化
|
|
|
+ */
|
|
|
+export const wholeLineReplacePoint = (
|
|
|
+ config: WholeLineAttrib,
|
|
|
+ originPointIds: string[],
|
|
|
+ replacePointId: string
|
|
|
+) => {
|
|
|
+ const change: WholeLineChange = {
|
|
|
+ pointChange: {
|
|
|
+ del: [],
|
|
|
+ },
|
|
|
+ lineChange: {
|
|
|
+ del: [],
|
|
|
+ add: [],
|
|
|
+ update: [],
|
|
|
+ },
|
|
|
+ polygonChange: {
|
|
|
+ del: [],
|
|
|
+ update: [],
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ for (let i = 0; i < config.polygons.length; i++) {
|
|
|
+ const polygon = config.polygons[i];
|
|
|
+ let initPolygonLineIds: string[];
|
|
|
+
|
|
|
+ for (const originPointId of originPointIds) {
|
|
|
+ const lineIds = polygon.lineIds;
|
|
|
+ for (let j = 0; j < lineIds.length; j++) {
|
|
|
+ const line = getWholeLineLineRaw(config, lineIds[j]);
|
|
|
+ let ndx = line.pointIds.indexOf(originPointId);
|
|
|
+ if (!~ndx) continue;
|
|
|
+ initPolygonLineIds = initPolygonLineIds || [...polygon.lineIds];
|
|
|
+
|
|
|
+ const repPoints = [...line.pointIds];
|
|
|
+ repPoints[ndx] = replacePointId;
|
|
|
+
|
|
|
+ // 如果前后是主点则删除线段
|
|
|
+ if (repPoints[0] === repPoints[1]) {
|
|
|
+ polygon.lineIds.splice(j, 1);
|
|
|
+ } else {
|
|
|
+ const adL = wholeLineAddLineByPointIds(config, repPoints);
|
|
|
+ polygon.lineIds[j] = adL.line.id;
|
|
|
+ change.lineChange.del.push(...adL.change.lineChange.add);
|
|
|
+ }
|
|
|
+
|
|
|
+ const dl = wholeLineDelLineByPointIds(config, line.pointIds);
|
|
|
+ change.lineChange.del.push(...dl.change.lineChange.del);
|
|
|
+ change.pointChange.del.push(...dl.change.pointChange.del);
|
|
|
+ j--;
|
|
|
+ }
|
|
|
+ // 如果合并后只剩一个点则直接删除整个polygon
|
|
|
+ if (initPolygonLineIds) {
|
|
|
+ const beforePolygon = { ...polygon, lineIds: initPolygonLineIds };
|
|
|
+ if (polygon.lineIds.length === 0) {
|
|
|
+ change.polygonChange.del.push(beforePolygon);
|
|
|
+ config.polygons.splice(i--, 1);
|
|
|
+ } else {
|
|
|
+ change.polygonChange.update.push({
|
|
|
+ before: beforePolygon,
|
|
|
+ after: polygon,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return change;
|
|
|
+};
|