|
|
@@ -4,7 +4,7 @@ import Graph from "../../graph/Graph.js";
|
|
|
import Layering from "../../graph/layering/Layering.js";
|
|
|
import Node from "../../graph/node/Node.js";
|
|
|
import AlgorithmStep from "../AlgorithmStep.js";
|
|
|
-import {FeedbackSet, SiguiyamaContext} from "../siguiyama/SiguiyamaContext.js";
|
|
|
+import {EdgeSubdivisions, FeedbackSet, SiguiyamaContext} from "../siguiyama/SiguiyamaContext.js";
|
|
|
import DummyNode from "../../graph/node/DummyNode.js";
|
|
|
import DummyEdge from "../../graph/edge/DummyEdge.js";
|
|
|
|
|
|
@@ -37,10 +37,12 @@ export default class LayerAssignmentStep extends AlgorithmStep<SiguiyamaContext>
|
|
|
throw new LayerAssignmentStepError("Graph is acyclic, can not assign layers to an acyclic graph!");
|
|
|
|
|
|
const layering = this.longestPathAlgorithm(graph);
|
|
|
+ const edgeSubdivisions: EdgeSubdivisions<Node, Edge<Node>> = new Map();
|
|
|
|
|
|
- this.divideLongEdges(graph, layering, feedbackSet);
|
|
|
+ this.divideLongEdges(graph, layering, feedbackSet, edgeSubdivisions);
|
|
|
|
|
|
context.layering = layering;
|
|
|
+ context.edgeSubdivisions = edgeSubdivisions;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -89,8 +91,9 @@ export default class LayerAssignmentStep extends AlgorithmStep<SiguiyamaContext>
|
|
|
* @param graph Граф, в который добавляются dummy-вершины и сегменты рёбер.
|
|
|
* @param layering Текущее разбиение графа на слои, используемое для вычисления span и вставки dummy-вершин.
|
|
|
* @param feedbackSet Набор рёбер обратной связи
|
|
|
- */
|
|
|
- private divideLongEdges(graph: Graph<Node, Edge<Node>>, layering: Layering<Node, Edge<Node>>, feedbackSet: FeedbackSet) : void {
|
|
|
+ * @param edgeSubdivisions Информация о разделении рёбер в графе
|
|
|
+ */
|
|
|
+ private divideLongEdges(graph: Graph<Node, Edge<Node>>, layering: Layering<Node, Edge<Node>>, feedbackSet: FeedbackSet, edgeSubdivisions: EdgeSubdivisions<Node, Edge<Node>>) : void {
|
|
|
const edges = graph.getEdges();
|
|
|
|
|
|
for(const edge of edges) {
|
|
|
@@ -100,28 +103,33 @@ export default class LayerAssignmentStep extends AlgorithmStep<SiguiyamaContext>
|
|
|
|
|
|
const from = edge.getFrom(), to = edge.getTo();
|
|
|
const fromLayer = layering.getNodeLayerIndex(from);
|
|
|
- const isReversed = feedbackSet.includes(edge);
|
|
|
+ let currentEdge: Edge<Node> = edge;
|
|
|
+
|
|
|
+ graph.removeEdge(edge.getId());
|
|
|
|
|
|
- let currentNode = from;
|
|
|
for(let i = 1; i < span; i++) {
|
|
|
- const dummyNode = new DummyNode(0, 0, edge.getId());
|
|
|
+ const dummyNode = new DummyNode(0, 0);
|
|
|
layering.addToLayer(fromLayer - i, dummyNode);
|
|
|
graph.addNode(dummyNode);
|
|
|
|
|
|
- const dummyEdge = new DummyEdge(currentNode, dummyNode, [], "dummy-" + crypto.randomUUID());
|
|
|
- graph.addEdge(dummyEdge);
|
|
|
- if(isReversed)
|
|
|
- feedbackSet.push(dummyEdge);
|
|
|
+ const left = new DummyEdge(currentEdge.getFrom(), dummyNode);
|
|
|
+ const right = new DummyEdge(dummyNode, currentEdge.getTo());
|
|
|
|
|
|
- currentNode = dummyNode;
|
|
|
- }
|
|
|
+ edgeSubdivisions.set(currentEdge, { left, right });
|
|
|
|
|
|
- const finalEdge = new DummyEdge(currentNode, to, [], "dummy-" + crypto.randomUUID());
|
|
|
- graph.addEdge(finalEdge);
|
|
|
- if(isReversed)
|
|
|
- feedbackSet.push(finalEdge);
|
|
|
+ graph.addEdge(left).addEdge(right);
|
|
|
|
|
|
- graph.removeEdge(edge.getId());
|
|
|
+ const feedbackIndex = feedbackSet.indexOf(currentEdge);
|
|
|
+ if(feedbackIndex >= 0) {
|
|
|
+ feedbackSet.splice(feedbackIndex, 1);
|
|
|
+ feedbackSet.push(left, right);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(currentEdge !== edge)
|
|
|
+ graph.removeEdge(currentEdge.getId());
|
|
|
+
|
|
|
+ currentEdge = right;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|