|
|
@@ -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 {SiguiyamaContext} from "../siguiyama/SiguiyamaContext.js";
|
|
|
+import {FeedbackSet, SiguiyamaContext} from "../siguiyama/SiguiyamaContext.js";
|
|
|
import DummyNode from "../../graph/node/DummyNode.js";
|
|
|
import DummyEdge from "../../graph/edge/DummyEdge.js";
|
|
|
|
|
|
@@ -38,7 +38,7 @@ export default class LayerAssignmentStep extends AlgorithmStep<SiguiyamaContext>
|
|
|
|
|
|
const layering = this.longestPathAlgorithm(graph);
|
|
|
|
|
|
- this.divideLongEdges(graph, layering);
|
|
|
+ this.divideLongEdges(graph, layering, feedbackSet);
|
|
|
|
|
|
context.layering = layering;
|
|
|
}
|
|
|
@@ -79,17 +79,18 @@ export default class LayerAssignmentStep extends AlgorithmStep<SiguiyamaContext>
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Разбивает длинные рёбра (span >= 2) добавлением dummy-вершин между слоями.
|
|
|
- *
|
|
|
- * Для каждого ребра, у которого {@link Layering.getEdgeSpan} возвращает значение больше 1:
|
|
|
- * - создаётся цепочка из `span - 1` вершин {@link DummyNode};
|
|
|
- * - каждая dummy-вершина добавляется в промежуточный слой;
|
|
|
- * - исходная вершина/последняя dummy соединяется новым сегментом {@link Edge}.
|
|
|
- *
|
|
|
- * @param graph Граф, в который добавляются dummy-вершины и сегменты рёбер.
|
|
|
- * @param layering Текущее разбиение графа на слои, используемое для вычисления span и вставки dummy-вершин.
|
|
|
+ * Разбивает длинные рёбра (span >= 2) добавлением dummy-вершин между слоями.
|
|
|
+ *
|
|
|
+ * Для каждого ребра, у которого {@link Layering.getEdgeSpan} возвращает значение больше 1:
|
|
|
+ * - создаётся цепочка из `span - 1` вершин {@link DummyNode};
|
|
|
+ * - каждая dummy-вершина добавляется в промежуточный слой;
|
|
|
+ * - исходная вершина/последняя dummy соединяется новым сегментом {@link Edge}.
|
|
|
+ *
|
|
|
+ * @param graph Граф, в который добавляются dummy-вершины и сегменты рёбер.
|
|
|
+ * @param layering Текущее разбиение графа на слои, используемое для вычисления span и вставки dummy-вершин.
|
|
|
+ * @param feedbackSet Набор рёбер обратной связи
|
|
|
*/
|
|
|
- private divideLongEdges(graph: Graph<Node, Edge<Node>>, layering: Layering<Node, Edge<Node>>) : void {
|
|
|
+ private divideLongEdges(graph: Graph<Node, Edge<Node>>, layering: Layering<Node, Edge<Node>>, feedbackSet: FeedbackSet) : void {
|
|
|
const edges = graph.getEdges();
|
|
|
|
|
|
for(const edge of edges) {
|
|
|
@@ -99,6 +100,7 @@ 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 currentNode = from;
|
|
|
for(let i = 1; i < span; i++) {
|
|
|
@@ -108,12 +110,16 @@ export default class LayerAssignmentStep extends AlgorithmStep<SiguiyamaContext>
|
|
|
|
|
|
const dummyEdge = new DummyEdge(currentNode, dummyNode, [], "dummy-" + crypto.randomUUID());
|
|
|
graph.addEdge(dummyEdge);
|
|
|
+ if(isReversed)
|
|
|
+ feedbackSet.push(dummyEdge);
|
|
|
|
|
|
currentNode = dummyNode;
|
|
|
}
|
|
|
|
|
|
const finalEdge = new DummyEdge(currentNode, to, [], "dummy-" + crypto.randomUUID());
|
|
|
graph.addEdge(finalEdge);
|
|
|
+ if(isReversed)
|
|
|
+ feedbackSet.push(finalEdge);
|
|
|
}
|
|
|
}
|
|
|
}
|