91 lines
3.6 KiB
TypeScript
91 lines
3.6 KiB
TypeScript
import { ConcreteSyntax, VisualEditorState } from "@/App/VisualEditor/VisualEditor";
|
|
import { findNearestArrow, findNearestHistory, findNearestSide, findRountangle, RectSide } from "./concrete_syntax";
|
|
|
|
export type Connections = {
|
|
arrow2SideMap: Map<string,[{ uid: string; part: RectSide; } | undefined, { uid: string; part: RectSide; } | undefined]>,
|
|
side2ArrowMap: Map<string, Set<["start"|"end", string]>>,
|
|
text2ArrowMap: Map<string,string>,
|
|
arrow2TextMap: Map<string,string[]>,
|
|
arrow2HistoryMap: Map<string,string>,
|
|
text2RountangleMap: Map<string, string>,
|
|
rountangle2TextMap: Map<string, string[]>,
|
|
history2ArrowMap: Map<string, string[]>,
|
|
}
|
|
|
|
export function detectConnections(state: ConcreteSyntax): Connections {
|
|
const startTime = performance.now();
|
|
// detect what is 'connected'
|
|
const arrow2SideMap = new Map<string,[{ uid: string; part: RectSide; } | undefined, { uid: string; part: RectSide; } | undefined]>();
|
|
const side2ArrowMap = new Map<string, Set<["start"|"end", string]>>();
|
|
const text2ArrowMap = new Map<string,string>();
|
|
const arrow2TextMap = new Map<string,string[]>();
|
|
const arrow2HistoryMap = new Map<string,string>();
|
|
const text2RountangleMap = new Map<string, string>();
|
|
const rountangle2TextMap = new Map<string, string[]>();
|
|
const history2ArrowMap = new Map<string, string[]>();
|
|
|
|
// arrow <-> (rountangle | diamond)
|
|
for (const arrow of state.arrows) {
|
|
// snap to history:
|
|
const historyTarget = findNearestHistory(arrow.end, state.history);
|
|
if (historyTarget) {
|
|
arrow2HistoryMap.set(arrow.uid, historyTarget.uid);
|
|
history2ArrowMap.set(historyTarget.uid, [...(history2ArrowMap.get(historyTarget.uid) || []), arrow.uid]);
|
|
}
|
|
|
|
// snap to rountangle/diamon side:
|
|
const sides = [...state.rountangles, ...state.diamonds];
|
|
const startSide = findNearestSide(arrow, "start", sides);
|
|
const endSide = historyTarget ? undefined : findNearestSide(arrow, "end", sides);
|
|
if (startSide || endSide) {
|
|
arrow2SideMap.set(arrow.uid, [startSide, endSide]);
|
|
}
|
|
if (startSide) {
|
|
const arrowConns = side2ArrowMap.get(startSide.uid + '/' + startSide.part) || new Set();
|
|
arrowConns.add(["start", arrow.uid]);
|
|
side2ArrowMap.set(startSide.uid + '/' + startSide.part, arrowConns);
|
|
}
|
|
if (endSide) {
|
|
const arrowConns = side2ArrowMap.get(endSide.uid + '/' + endSide.part) || new Set();
|
|
arrowConns.add(["end", arrow.uid]);
|
|
side2ArrowMap.set(endSide.uid + '/' + endSide.part, arrowConns);
|
|
}
|
|
}
|
|
// text <-> arrow
|
|
for (const text of state.texts) {
|
|
const nearestArrow = findNearestArrow(text.topLeft, state.arrows);
|
|
if (nearestArrow) {
|
|
// prioritize text belonging to arrows:
|
|
text2ArrowMap.set(text.uid, nearestArrow.uid);
|
|
const textsOfArrow = arrow2TextMap.get(nearestArrow.uid) || [];
|
|
textsOfArrow.push(text.uid);
|
|
arrow2TextMap.set(nearestArrow.uid, textsOfArrow);
|
|
}
|
|
else {
|
|
// text <-> rountangle
|
|
const rountangle = findRountangle(text.topLeft, state.rountangles);
|
|
if (rountangle) {
|
|
text2RountangleMap.set(text.uid, rountangle.uid);
|
|
const texts = rountangle2TextMap.get(rountangle.uid) || [];
|
|
texts.push(text.uid);
|
|
rountangle2TextMap.set(rountangle.uid, texts);
|
|
}
|
|
}
|
|
}
|
|
|
|
const endTime = performance.now();
|
|
|
|
// rather slow, about 10ms for a large model:
|
|
// console.debug("connection detection took", endTime-startTime);
|
|
|
|
return {
|
|
arrow2SideMap,
|
|
side2ArrowMap,
|
|
text2ArrowMap,
|
|
arrow2TextMap,
|
|
arrow2HistoryMap,
|
|
text2RountangleMap,
|
|
rountangle2TextMap,
|
|
history2ArrowMap,
|
|
};
|
|
}
|