bill 1 month ago
parent
commit
bc64aebd50

+ 15 - 15
src/core/components/line/attach-server.ts

@@ -4,7 +4,7 @@ import {
   useSnap,
   useSnapConfig,
 } from "@/core/hook/use-snap";
-import { defaultStyle, getSnapInfos, LineData } from ".";
+import { defaultStyle, getSnapInfos, LineData, LineDataLine } from ".";
 import {
   eqPoint,
   getVectorLine,
@@ -37,7 +37,7 @@ import {
   useRunHook,
   useStage,
 } from "@/core/hook/use-global-vars";
-import { mergeDescribes, PropertyDescribes } from "@/core/html-mount/propertys";
+import { PropertyDescribes } from "@/core/html-mount/propertys";
 import { useMode } from "@/core/hook/use-status";
 import { useListener } from "@/core/hook/use-event";
 import { Mode } from "@/constant/mode";
@@ -54,15 +54,15 @@ import { useComponentDescribes } from "@/core/hook/use-component";
 export type NLineDataCtx = {
   del: {
     points: Record<string, LineData["points"][0]>;
-    lines: Record<string, LineData["lines"][0]>;
+    lines: Record<string, LineDataLine>;
   };
   add: {
     points: Record<string, LineData["points"][0]>;
-    lines: Record<string, LineData["lines"][0]>;
+    lines: Record<string, LineDataLine>;
   };
   update: {
     points: Record<string, LineData["points"][0]>;
-    lines: Record<string, LineData["lines"][0]>;
+    lines: Record<string, LineDataLine>;
   };
 };
 export const getInitCtx = (): NLineDataCtx => ({
@@ -106,13 +106,13 @@ export const repPointRef = (
   return data;
 };
 
-export const getLinePoints = (data: LineData, line: LineData["lines"][0]) => [
+export const getLinePoints = (data: LineData, line: LineDataLine) => [
   data.points.find((p) => p.id === line.a)!,
   data.points.find((p) => p.id === line.b)!,
 ];
 
 export const deduplicateLines = (data: LineData) => {
-  const seen = new Map<string, LineData["lines"][0]>();
+  const seen = new Map<string, LineDataLine>();
   let isChange = false;
   for (const line of data.lines) {
     if (line.a === line.b) continue;
@@ -142,7 +142,7 @@ export const deduplicateLines = (data: LineData) => {
 
 export const getJoinLine = (
   data: LineData,
-  line: LineData["lines"][0],
+  line: LineDataLine,
   pId: string
 ) => {
   const pointIds = [line.a, line.b];
@@ -511,7 +511,7 @@ export const useLineDataSnapInfos = () => {
 
 export const updateLineLength = (
   lineData: LineData,
-  line: LineData["lines"][0],
+  line: LineDataLine,
   length: number,
   flex?: "a" | "b" | "both",
   vector?: Pos
@@ -564,7 +564,7 @@ export const updateLineLength = (
   Object.assign(points[1], npoints[1]);
 };
 
-export const useLineDescribes = (line: Ref<LineData["lines"][0]>) => {
+export const useLineDescribes = (line: Ref<LineDataLine>) => {
   const d: any = useComponentDescribes(line, ["stroke", "strokeWidth"], {});
   const store = useStore();
   const lineData = computed(() => store.getTypeItems("line")[0]);
@@ -609,10 +609,10 @@ export const useLineDescribes = (line: Ref<LineData["lines"][0]>) => {
 
 export const useDrawLinePoint = (
   data: LineData,
-  line: LineData["lines"][0],
+  line: LineDataLine,
   callback: (data: {
-    prev: LineData["lines"][0];
-    next: LineData["lines"][0];
+    prev: LineDataLine;
+    next: LineDataLine;
     point: LineData["points"][0];
     oldIcons: LineIconData[];
     newIcons: LineIconData[];
@@ -634,8 +634,8 @@ export const useDrawLinePoint = (
   const viewInvMat = useViewerInvertTransform();
   const drawProps = ref<{
     data: LineData;
-    prev: LineData["lines"][0];
-    next: LineData["lines"][0];
+    prev: LineDataLine;
+    next: LineDataLine;
     point: LineData["points"][0];
   }>();
   const runHook = useRunHook();

+ 109 - 115
src/core/components/line/attach-view.ts

@@ -1,8 +1,14 @@
 import {
   eqPoint,
   getDiffPolygons,
+  getLEJLineAngle,
+  getLineEdgeJoinInfo,
+  getLineEdges,
   getVectorLine,
   isPolygonPointInner,
+  LEJInfo,
+  LEJLine,
+  line2IncludedAngle,
   lineCenter,
   lineInner,
   lineIntersection,
@@ -13,8 +19,8 @@ import {
   vector2IncludedAngle,
   verticalVector,
 } from "@/utils/math";
-import { LineData } from ".";
-import { getJoinLine } from "./attach-server";
+import { LineData, LineDataLine } from ".";
+import { getJoinLine, getLinePoints } from "./attach-server";
 import { MathUtils } from "three";
 import { diffArrayChange, rangMod } from "@/utils/shared";
 import { globalWatch, installGlobalVar } from "@/core/hook/use-global-vars";
@@ -24,137 +30,122 @@ 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;
-      }
+  const minAngle = MathUtils.degToRad(0.1);
+  const palAngle = MathUtils.degToRad(20);
+  const linePolygons: Record<string, Pos[]> = reactive({});
 
-      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]];
-      }
+  const lineJoinInfos = reactive({}) as Record<
+    string,
+    Record<string, LEJInfo | undefined>
+  >;
 
-      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 getInfoKey = (line: LEJLine) =>
+    line.points.reduce((t, p) => p.x + p.y + t, "") + line.width;
+
+  const updateLine2JoinInfo = (
+    data: LineData,
+    line1: LineDataLine,
+    line2: LineDataLine
+  ) => {
 
-      const outer = lineIntersection(outerLine1, outerLine2);
-      if (!outer) return;
+  };
 
-      let inside: Pos = lineIntersection(innerLine1, innerLine2)!;
-      if (!inside) return;
+  const getLineInfo = (data: LineData, line: LineDataLine) => {
+    const origin = {
+      points: getLinePoints(data, line),
+      width: line.strokeWidth,
+    };
+    const key = getInfoKey(origin);
+    if (!(key in lineJoinInfos)) {
+      lineJoinInfos[key] = {};
+    }
 
-      const insideLineInner1 = lineInner(innerLine1, inside);
-      const insideLineInner2 = lineInner(innerLine2, inside);
+    const cache = lineJoinInfos[key];
+    const exist0 = "0" in cache;
+    const exist1 = "1" in cache;
+    if (exist0 && exist1) {
+      return [cache[0], cache[1]];
+    }
 
-      if (!insideLineInner1 && !insideLineInner2) return;
+    const calcNdxs: number[] = [];
+    exist0 || calcNdxs.push(0);
+    exist1 || calcNdxs.push(1);
+
+    const update2Line = (join: LineDataLine, originNdx: number) => {
+      const target = {
+        points: getLinePoints(data, join),
+        width: join.strokeWidth,
+      };
+      const joinInfo = getLineEdgeJoinInfo(origin, target, minAngle, palAngle);
+      cache[originNdx] = joinInfo?.origin;
+
+      const targetKey = getInfoKey(target);
+      if (!(targetKey in lineJoinInfos)) {
+        lineJoinInfos[targetKey] = {};
+      }
+      const p = origin.points[originNdx];
+      lineJoinInfos[targetKey][target.points.indexOf(p)] = joinInfo?.target;
+    };
 
-      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 updateManyLine = (joins: LineDataLine[], originNdx: number) => {
+      let maxAngle = minAngle;
+      let select: ReturnType<typeof getLEJLineAngle> & {
+        origin: LineDataLine;
+        target: LineDataLine;
+      };
+      for (let i = 0; i < joins.length; i++) {
+        const line1 = getLinePoints(data, joins[i]);
+        for (let j = i + 1; j < joins.length; j++) {
+          const line2 = getLinePoints(data, joins[j]);
+          if (line2IncludedAngle(line1, line2)) {
+            const ejlAngle = getLEJLineAngle(line1, line2);
+            if (ejlAngle.angle > maxAngle) {
+              maxAngle = ejlAngle.angle;
+              select = {
+                ...ejlAngle,
+                origin: joins[i],
+                target: joins[j],
+              };
+            }
+          }
+        }
       }
+    };
 
-      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 });
+    for (const ndx of calcNdxs) {
+      const p = origin.points[ndx];
+      const joins = getJoinLine(data, line, p.id);
+
+      if (joins.length === 0) {
+        cache[ndx] = undefined;
+      } else if (joins.length !== 1) {
+        updateManyLine(joins, ndx);
       } else {
-        repsResult.push({ rep: 1, points: rectJust ? outers : insides });
-        repsResult.push({
-          rep: 2,
-          points: rectJust ? insides : outers.reverse(),
-        });
+        update2Line(joins[0], ndx);
       }
-      // testPoints.value.push(...insides, ...outers);
-      return repsResult;
-    };
+    }
+    return [cache[0], cache[1]];
+  };
 
-    const linePoints = [line.a, line.b].map(
-      (id) => data.points.find((item) => item.id === id)!
+  return (data: LineData, line: LineDataLine, useJoin = true) => {
+    const originEdges: Pos[] = getLineEdges(
+      getLinePoints(data, line),
+      line.strokeWidth
     );
-    const lineRect: Pos[] = getLineRect(linePoints, line.strokeWidth);
-    const polygon = [...lineRect];
-    const linev = lineVector(linePoints);
+    const initOriginEdges = [...originEdges];
     if (!useJoin) {
-      return polygon;
+      return originEdges;
     }
-
-    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);
+    getLineInfo(data, line).forEach((info) => {
+      if (!info) return;
+      for (const rep of info) {
+        const ndx = originEdges.indexOf(initOriginEdges[rep.rep]);
+        originEdges.splice(ndx, 1, ...rep.points);
       }
     });
-
-    return polygon;
+    return originEdges;
   };
 });
 
@@ -213,7 +204,10 @@ export const useGetDiffIconPolygons = installGlobalVar(() => {
 });
 
 // 计算与icon相差的多边形
-export const useGetDiffLineIconPolygons = (line: LineData["lines"][0], linePoints: Ref<Pos[]>) => {
+export const useGetDiffLineIconPolygons = (
+  line: LineDataLine,
+  linePoints: Ref<Pos[]>
+) => {
   const store = useStore();
   const drawStore = useDrawIngData();
   const linevv = computed(() => verticalVector(lineVector(linePoints.value!)));

+ 37 - 32
src/core/components/line/index.ts

@@ -5,7 +5,10 @@ import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts";
 import { inRevise, onlyId, rangMod } from "@/utils/shared.ts";
 import { MathUtils } from "three";
 import { DrawStore, useStore } from "@/core/store/index.ts";
-import { SelectionManageBus, UseGetSelectionManage } from "@/core/hook/use-selection.ts";
+import {
+  SelectionManageBus,
+  UseGetSelectionManage,
+} from "@/core/hook/use-selection.ts";
 import { EntityShape } from "@/deconstruction.js";
 import mitt from "mitt";
 import { watch } from "vue";
@@ -58,17 +61,19 @@ export const getSnapPoints = (data: LineData) => {
   return data.points;
 };
 
+export type LineDataLine = {
+  id: string;
+  a: string;
+  b: string;
+  strokeWidth: number;
+  stroke: string;
+  dash: number[];
+};
+export type LineDataPoint = Pos & { id: string }
 export type LineData = Partial<typeof defaultStyle> &
   BaseItem & {
-    points: (Pos & { id: string })[];
-    lines: {
-      id: string;
-      a: string;
-      b: string;
-      strokeWidth: number;
-      stroke: string;
-      dash: number[];
-    }[];
+    points: LineDataPoint[];
+    lines: LineDataLine[];
     polygon: { points: string[]; id: string }[];
     updateTime?: number;
     calcTime?: number;
@@ -131,44 +136,44 @@ export const interactiveFixData: InteractiveFix<"line"> = ({ data, info }) => {
   return data;
 };
 
-const matResPoints = new Set<string>()
-let matCtx: NLineDataCtx | null
+const matResPoints = new Set<string>();
+let matCtx: NLineDataCtx | null;
 export const startMatResponse = () => {
-  matCtx = getInitCtx()
-}
+  matCtx = getInitCtx();
+};
 
 export const matResponse = ({
   data,
   mat,
-  operId
+  operId,
 }: MatResponseProps<"line">) => {
-  const line =  data.lines.find(item => item.id === operId)
+  const line = data.lines.find((item) => item.id === operId);
   if (!line) return;
-  const ids = [line.a, line.b]
+  const ids = [line.a, line.b];
   for (const id of ids) {
     if (matResPoints.has(id)) {
       continue;
     }
-    const ndx = data.points.findIndex(item => item.id === id)
+    const ndx = data.points.findIndex((item) => item.id === id);
     if (~ndx) {
-      const point = data.points[ndx]
+      const point = data.points[ndx];
       data.points[ndx] = {
         ...point,
-        ...mat.point(point)
-      }
-      matCtx!.update.points[point.id] = data.points[ndx]
-      matResPoints.add(id)
+        ...mat.point(point),
+      };
+      matCtx!.update.points[point.id] = data.points[ndx];
+      matResPoints.add(id);
     }
   }
   return data;
 };
 
 export const endMatResponse = () => {
-  matResPoints.clear()
+  matResPoints.clear();
   // matCtx && normalLineData(matData, matCtx)
   // console.log(matData, matCtx)
-  matCtx = null
-}
+  matCtx = null;
+};
 
 export const getPredefine = (key: keyof LineData) => {
   if (key === "strokeWidth") {
@@ -177,12 +182,12 @@ export const getPredefine = (key: keyof LineData) => {
 };
 
 export const childrenDataGetter = (data: LineData, id: string) => {
-  const line = data.lines.find(item => item.id === id)
+  const line = data.lines.find((item) => item.id === id);
   if (!line) return;
 
-  const ids = [line.a, line.b]
-  return data.points.filter(p => ids.includes(p.id))
-}
+  const ids = [line.a, line.b];
+  return data.points.filter((p) => ids.includes(p.id));
+};
 
 export const delItem = (store: DrawStore, data: LineData, childId: string) => {
   if (!childId) {
@@ -251,8 +256,8 @@ export const useGetSelectionManage: UseGetSelectionManage = () => {
 
   const canSelect = (shape: EntityShape) => {
     const id = shape.id();
-    const line = store.getTypeItems('line')[0]
-    return !!(id && line.lines.some(item => item.id === id));
+    const line = store.getTypeItems("line")[0];
+    return !!(id && line.lines.some((item) => item.id === id));
   };
   const listener = (shape: EntityShape) => {
     const bus: SelectionManageBus = mitt();

+ 204 - 1
src/utils/math.ts

@@ -1,6 +1,6 @@
 import { Vector2, ShapeUtils, Box2 } from "three";
 import { Transform } from "konva/lib/Util";
-import { flatPositions, round } from "./shared.ts";
+import { flatPositions, rangMod, round } from "./shared.ts";
 import { IRect } from "konva/lib/types";
 import { diff as diffPolygons, MultiPolygon } from "martinez-polygon-clipping";
 
@@ -660,3 +660,206 @@ export const getDiffPolygons = (
     return [originPolygon];
   }
 };
+
+export const getLineEdges = (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 type LEJLine = { points: Pos[]; width: number };
+export type LEJInfo = { rep: number; points: Pos[] }[];
+export const getLEJLineAngle = (originLine: Pos[], targetLine: Pos[]) => {
+  let originNdx = -1,
+    targetNdx = -1;
+  for (let i = 0; i < originLine.length; i++) {
+    targetNdx = targetLine.findIndex((p) => eqPoint(originLine[i], p));
+    if (~targetNdx) {
+      originNdx = i;
+      break;
+    }
+  }
+
+  const targetInvFlag = originNdx === targetNdx;
+  const targetPoints = targetInvFlag ? [...targetLine].reverse() : targetLine;
+  const originVector = lineVector(originLine);
+  const targetVector = lineVector(targetPoints).multiplyScalar(-1);
+
+  let angle;
+  if (originNdx === targetNdx && originNdx === 0) {
+    angle = vector2IncludedAngle(targetVector, originVector);
+  } else {
+    angle = vector2IncludedAngle(originVector, targetVector);
+  }
+  return {
+    angle,
+    originNdx,
+    targetNdx,
+    targetPoints,
+  };
+};
+/**
+ * 获取两变短延伸后的平湖处理
+ * @param origin
+ * @param target
+ * @param minAngle
+ * @param palAngle
+ * @returns 平滑信息,需要结合延伸使用
+ */
+export const getLineEdgeJoinInfo = (
+  origin: LEJLine,
+  target: LEJLine,
+  minAngle: number,
+  palAngle: number
+) => {
+  const {
+    angle,
+    originNdx,
+    targetNdx,
+    targetPoints
+  } = getLEJLineAngle(origin.points, target.points)
+
+  // 最小可平滑处理角度
+  const norAngle = rangMod(Math.abs(angle), Math.PI);
+  if (norAngle < minAngle || norAngle > Math.PI - minAngle) {
+    return;
+  }
+
+  const targetEdges = getLineEdges(targetPoints, target.width);
+  const originEdges = getLineEdges(origin.points, origin.width);
+
+  const targetJoinNdxs = originNdx === 0 ? [0, 3] : [1, 2];
+  const originJoinNdxs = originNdx === 0 ? [1, 2] : [0, 3];
+  // 如果交点边缘在另一条线中则不处理
+  if (
+    originJoinNdxs.some((i) =>
+      isPolygonPointInner(targetEdges, originEdges[i])
+    ) ||
+    targetJoinNdxs.some((i) => isPolygonPointInner(originEdges, targetEdges[i]))
+  ) {
+    return;
+  }
+
+  const center = lineCenter([...origin.points, ...target.points]);
+
+  const originEdgesInv =
+    lineLen(center, originEdges[0]) > lineLen(center, originEdges[3]);
+  let originInner, originOuter;
+  if (originEdgesInv) {
+    originOuter = [originEdges[0], originEdges[1]];
+    originInner = [originEdges[3], originEdges[2]];
+  } else {
+    originInner = [originEdges[0], originEdges[1]];
+    originOuter = [originEdges[3], originEdges[2]];
+  }
+
+  const targetEdgesInv =
+    lineLen(center, targetEdges[0]) > lineLen(center, targetEdges[3]);
+  let targetInner, targetOuter;
+  if (targetEdgesInv) {
+    targetOuter = [targetEdges[0], targetEdges[1]];
+    targetInner = [targetEdges[3], targetEdges[2]];
+  } else {
+    targetInner = [targetEdges[0], targetEdges[1]];
+    targetOuter = [targetEdges[3], targetEdges[2]];
+  }
+
+  const outerJoin = lineIntersection(targetOuter, originOuter);
+  if (!outerJoin) {
+    return;
+  }
+
+  const innerJoin = lineIntersection(targetInner, originInner);
+  if (!innerJoin) {
+    return;
+  }
+
+  // 如果内交点均不在两条内线上则不处理
+  if (
+    !lineInner(targetInner, innerJoin) &&
+    !lineInner(originInner, innerJoin)
+  ) {
+    return;
+  }
+
+  let targetInnerPoints: Pos[] = [innerJoin];
+  let targetOuterPoints: Pos[] = [outerJoin];
+  let originInnerPoints: Pos[] = [innerJoin];
+  let originOuterPoints: Pos[] = [outerJoin];
+
+  const join = origin.points[originNdx];
+  // 如果角度过于尖锐则使用平行线
+  if (norAngle < palAngle) {
+    const pal = getVectorLine(lineVerticalVector([join, outerJoin]), join);
+    originOuterPoints = [lineIntersection(pal, originOuter)!, join];
+    targetOuterPoints = [lineIntersection(pal, targetOuter)!, join];
+  }
+
+  const originRepInfos: LEJInfo = [];
+  const targetRepInfos: LEJInfo = [];
+
+  if (originNdx === 0) {
+    originRepInfos.push(
+      {
+        rep: 0,
+        points: originEdgesInv
+          ? originOuterPoints.reverse()
+          : originInnerPoints,
+      },
+      {
+        rep: 3,
+        points: originEdgesInv ? originInnerPoints : originOuterPoints,
+      }
+    );
+  } else {
+    originRepInfos.push(
+      {
+        rep: 1,
+        points: originEdgesInv ? originOuterPoints : originInnerPoints,
+      },
+      {
+        rep: 2,
+        points: originEdgesInv
+          ? originInnerPoints
+          : originOuterPoints.reverse(),
+      }
+    );
+  }
+
+  if (targetNdx === 0) {
+    targetRepInfos.push(
+      {
+        rep: 0,
+        points: targetEdgesInv
+          ? targetOuterPoints.reverse()
+          : targetInnerPoints,
+      },
+      {
+        rep: 3,
+        points: targetEdgesInv ? targetInnerPoints : targetOuterPoints,
+      }
+    );
+  } else {
+    targetRepInfos.push(
+      {
+        rep: 1,
+        points: targetEdgesInv ? targetOuterPoints : targetInnerPoints,
+      },
+      {
+        rep: 2,
+        points: targetEdgesInv
+          ? targetInnerPoints
+          : targetOuterPoints.reverse(),
+      }
+    );
+  }
+
+  return {
+    target: targetRepInfos,
+    origin: originRepInfos,
+  };
+};