|
|
@@ -5,6 +5,7 @@ import Layering from "../../graph/layering/Layering.js";
|
|
|
import Node from "../../graph/node/Node.js";
|
|
|
import AlgorithmStep from "../AlgorithmStep.js";
|
|
|
import {SiguiyamaContext} from "../siguiyama/SiguiyamaContext.js";
|
|
|
+import DummyNode from "../../graph/node/DummyNode.js";
|
|
|
|
|
|
/**
|
|
|
* Шаг алгоритма Sugiyama для присвоения слоёв вершинам графа.
|
|
|
@@ -36,7 +37,11 @@ export default class LayerAssignmentStep extends AlgorithmStep<SiguiyamaContext>
|
|
|
if(!graph.isAcyclic())
|
|
|
throw new LayerAssignmentStepError("Graph is acyclic, can not assign layers to an acyclic graph!");
|
|
|
|
|
|
- context.layering = this.longestPathAlgorithm(graph);
|
|
|
+ const layering = this.longestPathAlgorithm(graph);
|
|
|
+
|
|
|
+ this.divideLongEdges(graph, layering);
|
|
|
+
|
|
|
+ context.layering = layering;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -73,4 +78,40 @@ export default class LayerAssignmentStep extends AlgorithmStep<SiguiyamaContext>
|
|
|
|
|
|
return layering;
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Разбивает длинные рёбра (span >= 2) добавлением dummy-вершин между слоями.
|
|
|
+ *
|
|
|
+ * Для каждого ребра, у которого {@link Layering.getEdgeSpan} возвращает значение больше 1:
|
|
|
+ * - создаётся цепочка из `span - 1` вершин {@link DummyNode};
|
|
|
+ * - каждая dummy-вершина добавляется в промежуточный слой;
|
|
|
+ * - исходная вершина/последняя dummy соединяется новым сегментом {@link Edge}.
|
|
|
+ *
|
|
|
+ * @param graph Граф, в который добавляются dummy-вершины и сегменты рёбер.
|
|
|
+ * @param layering Текущее разбиение графа на слои, используемое для вычисления span и вставки dummy-вершин.
|
|
|
+ */
|
|
|
+ private divideLongEdges(graph: Graph<Node, Edge<Node>>, layering: Layering<Node, Edge<Node>>) : void {
|
|
|
+ const edges = graph.getEdges();
|
|
|
+
|
|
|
+ for(const edge of edges) {
|
|
|
+ const span = layering.getEdgeSpan(edge);
|
|
|
+ if(span < 2)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ const from = edge.getFrom();
|
|
|
+ const fromLayer = layering.getNodeLayerIndex(from);
|
|
|
+
|
|
|
+ let currentNode = from;
|
|
|
+ for(let i = 1; i < span; i++) {
|
|
|
+ const dummyNode = new DummyNode(0, 0, edge.getId());
|
|
|
+ layering.addToLayer(fromLayer - i, dummyNode);
|
|
|
+ graph.addNode(dummyNode);
|
|
|
+
|
|
|
+ const dummyEdge = new Edge(currentNode, dummyNode);
|
|
|
+ graph.addEdge(dummyEdge);
|
|
|
+
|
|
|
+ currentNode = dummyNode;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|