EdgeRoutingStep.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import AlgorithmStep from "../AlgorithmStep.js";
  2. import {EdgeSubdivisions, SiguiyamaContext} from "../siguiyama/SiguiyamaContext.js";
  3. import EdgeRoutingStepError from "../../errors/optimizer/EdgeRoutingStepError.js";
  4. import Node from "../../graph/node/Node.js";
  5. import Edge from "../../graph/edge/Edge.js";
  6. import DummyNode from "../../graph/node/DummyNode.js";
  7. import DummyEdge from "../../graph/edge/DummyEdge.js";
  8. import Graph from "../../graph/Graph.js";
  9. import Layering from "../../graph/layering/Layering.js";
  10. export default class EdgeRoutingStep extends AlgorithmStep<SiguiyamaContext> {
  11. public constructor() {
  12. super(EdgeRoutingStep.name);
  13. }
  14. public run(context: SiguiyamaContext) : void {
  15. const { layering, graph, edgeSubdivisions } = context;
  16. if(!layering)
  17. throw new EdgeRoutingStepError("Layering is null or undefined");
  18. if(!graph)
  19. throw new EdgeRoutingStepError("Graph is null or undefined");
  20. if(!edgeSubdivisions)
  21. throw new EdgeRoutingStepError("Edge Subdivisions are null or undefined");
  22. this.routeEdges(graph, layering, edgeSubdivisions);
  23. }
  24. private routeEdges(graph: Graph<Node, Edge<Node>>, layering: Layering<Node, Edge<Node>>, edgeSubdivisions: EdgeSubdivisions<Node, Edge<Node>>): void {
  25. const edges = graph.getEdges();
  26. for(const edge of edges) {
  27. const from = edge.getFrom();
  28. const to = edge.getTo();
  29. const fromNodeIndex = this.getNodeIndex(layering, from);
  30. const toNodeIndex = this.getNodeIndex(layering, to);
  31. if(fromNodeIndex === -1 || toNodeIndex === -1 || fromNodeIndex === toNodeIndex)
  32. continue;
  33. const fromLayerIndex = layering.getNodeLayerIndex(from);
  34. if(fromLayerIndex === -1)
  35. continue;
  36. const targetRowIndex = fromNodeIndex > toNodeIndex ? fromNodeIndex - 1 : fromNodeIndex + 1;
  37. const neighborRowCenter = this.getRowCenter(layering, targetRowIndex);
  38. if(neighborRowCenter === null)
  39. continue;
  40. const fromCenterY = from.getY() + from.getHeight() / 2;
  41. const routedNode = new DummyNode(
  42. from.getX() + from.getWidth() / 2,
  43. (fromCenterY + neighborRowCenter) / 2
  44. );
  45. layering.addToLayer(fromLayerIndex, routedNode);
  46. graph.addNode(routedNode);
  47. const left = new DummyEdge(from, routedNode);
  48. const right = new DummyEdge(routedNode, to);
  49. graph.addEdge(left);
  50. graph.addEdge(right);
  51. graph.removeEdge(edge.getId());
  52. edgeSubdivisions.set(edge, { left, right });
  53. }
  54. }
  55. private getRowCenter(layering: Layering<Node, Edge<Node>>, rowIndex: number): number | null {
  56. if(rowIndex < 0)
  57. return null;
  58. for(const layer of layering.getLayers()) {
  59. const node = layer.getNodes().at(rowIndex);
  60. if(node)
  61. return node.getY() + node.getHeight() / 2;
  62. }
  63. return null;
  64. }
  65. private getNodeIndex(layering: Layering<Node, Edge<Node>>, node: Node) : number {
  66. const layerIndex = layering.getNodeLayerIndex(node);
  67. if(layerIndex === -1)
  68. return -1;
  69. return layering.getLayers()[layerIndex]!.getNodes().indexOf(node);
  70. }
  71. }