|
|
@@ -0,0 +1,71 @@
|
|
|
+import AlgorithmStep from "../AlgorithmStep.js";
|
|
|
+import {SiguiyamaContext} from "../siguiyama/SiguiyamaContext.js";
|
|
|
+import EdgeRoutingStepError from "../../errors/optimizer/EdgeRoutingStepError.js";
|
|
|
+import Node from "../../graph/node/Node.js";
|
|
|
+import Edge from "../../graph/edge/Edge.js";
|
|
|
+import DummyNode from "../../graph/node/DummyNode.js";
|
|
|
+import DummyEdge from "../../graph/edge/DummyEdge.js";
|
|
|
+
|
|
|
+export default class EdgeRoutingStep extends AlgorithmStep<SiguiyamaContext> {
|
|
|
+ public constructor() {
|
|
|
+ super(EdgeRoutingStep.name);
|
|
|
+ }
|
|
|
+
|
|
|
+ public run(context: SiguiyamaContext) : void {
|
|
|
+ const { layering, graph } = context;
|
|
|
+
|
|
|
+ if(!layering)
|
|
|
+ throw new EdgeRoutingStepError("Layering is null or undefined");
|
|
|
+ if(!graph)
|
|
|
+ throw new EdgeRoutingStepError("Graph is null or undefined");
|
|
|
+
|
|
|
+ this.routeEdges(graph.getEdges(), layering, graph);
|
|
|
+ }
|
|
|
+
|
|
|
+ private routeEdges(edges: Edge<Node>[], layering: NonNullable<SiguiyamaContext["layering"]>, graph: NonNullable<SiguiyamaContext["graph"]>): void {
|
|
|
+ const layers = layering.getLayers();
|
|
|
+
|
|
|
+ for(const edge of edges) {
|
|
|
+ const from = edge.getFrom();
|
|
|
+ const to = edge.getTo();
|
|
|
+
|
|
|
+ const fromLayerIndex = layering.getNodeLayerIndex(from);
|
|
|
+ const toLayerIndex = layering.getNodeLayerIndex(to);
|
|
|
+
|
|
|
+ if(fromLayerIndex < 0 || toLayerIndex < 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ const fromRowIndex = layers[fromLayerIndex]?.getNodes().findIndex(node => node === from) ?? -1;
|
|
|
+ const toRowIndex = layers[toLayerIndex]?.getNodes().findIndex(node => node === to) ?? -1;
|
|
|
+
|
|
|
+ if(fromRowIndex < 0 || toRowIndex < 0 || fromRowIndex === toRowIndex)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ const rightLayer = layers[fromLayerIndex - 1];
|
|
|
+ if(!rightLayer)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ const rightLayerNodes = rightLayer.getNodes();
|
|
|
+ if(rightLayerNodes.length === 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ const anchorNode = rightLayerNodes[0]!;
|
|
|
+ const routedNode = new DummyNode(
|
|
|
+ anchorNode.getX() + anchorNode.getWidth() / 2,
|
|
|
+ from.getY() + from.getHeight() / 2,
|
|
|
+ edge.getId()
|
|
|
+ );
|
|
|
+
|
|
|
+ layering.addToLayer(fromLayerIndex - 1, routedNode);
|
|
|
+ graph.addNode(routedNode);
|
|
|
+
|
|
|
+ const firstSegment = new DummyEdge(from, routedNode, []);
|
|
|
+ const secondSegment = new DummyEdge(routedNode, to, []);
|
|
|
+
|
|
|
+ graph.addEdge(firstSegment);
|
|
|
+ graph.addEdge(secondSegment);
|
|
|
+ graph.removeEdge(edge.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|