Skip to content

Commit

Permalink
Fix missing routing of self-edges in vertical layout (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
phschaad authored Jul 20, 2023
1 parent 4267ba6 commit 3c35584
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 12 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@spcl/sdfv",
"version": "1.0.38",
"version": "1.1.0",
"description": "A standalone viewer for SDFGs",
"homepage": "https://github.com/spcl/dace-webclient",
"main": "out/index.js",
Expand Down
33 changes: 24 additions & 9 deletions src/layouter/state_machine/sm_layouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ const dagreOrder = require('dagre/lib/order');
const ARTIFICIAL_START = '__smlayouter_artifical_start';
const ARTIFICIAL_END = '__smlayouter_artifical_end';

const LAYER_SPACING = 50;
const NODE_SPACING = 50;
const BACKEDGE_SPACING = 20;
const SKIP_EDGES_CENTER_OFFSET = 50; // Given in percent.
export const LAYER_SPACING = 50;
export const NODE_SPACING = 50;
export const BACKEDGE_SPACING = 20;
export const SKIP_EDGES_CENTER_OFFSET = 50; // Given in percent.

enum ScopeType {
BRANCH,
Expand Down Expand Up @@ -824,7 +824,7 @@ export class SMLayouter {

for (const edge of this.graph.edgesIter()) {
// Here we don't want to route backedges, they are handled
// separately.
// separately (except for self edges).
const srcRank = this.graph.get(edge[0])!.rank!;
const dstRank = this.graph.get(edge[1])!.rank!;
if (srcRank > dstRank)
Expand All @@ -833,10 +833,25 @@ export class SMLayouter {
const edgeData = this.graph.edge(edge[0], edge[1])!;
const src = this.graph.get(edge[0])!;
const dst = this.graph.get(edge[1])!;
edgeData.points = [
{ x: src.x, y: src.y + (src.height / 2) },
{ x: dst.x, y: dst.y - (dst.height / 2) },
];

if (edge[0] === edge[1]) {
// Self edge.
const nodeLeftX = src.x - (src.width / 2);
const edgeLeftX = nodeLeftX - BACKEDGE_SPACING;
const edgeBottomY = src.y + (src.height / 4);
const edgeTopY = src.y - (src.height / 4);
edgeData.points = [
{ x: nodeLeftX, y: edgeBottomY },
{ x: edgeLeftX, y: edgeBottomY },
{ x: edgeLeftX, y: edgeTopY },
{ x: nodeLeftX, y: edgeTopY },
];
} else {
edgeData.points = [
{ x: src.x, y: src.y + (src.height / 2) },
{ x: dst.x, y: dst.y - (dst.height / 2) },
];
}
routedEdges.add(edgeData);
}

Expand Down
43 changes: 41 additions & 2 deletions tests/unit/layouter/state_machine/sm_layouter.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { DiGraph } from '../../../../src/layouter/graphlib/di_graph';
import {
BACKEDGE_SPACING,
SMLayouter,
SMLayouterEdge,
SMLayouterNode,
SMLayouterNode
} from '../../../../src/layouter/state_machine/sm_layouter';
import { DiGraph } from '../../../../src/layouter/graphlib/di_graph';

function constructNode(
graph: DiGraph<SMLayouterNode, SMLayouterEdge>, id: string, height?: number,
Expand Down Expand Up @@ -226,3 +227,41 @@ describe('Test vertical state machine layout ranking', () => {
);
test('Test self loops', testSelfLoop);
});

function testEdgeRoutingSelfLoop(): void {
const graph = new DiGraph<SMLayouterNode, SMLayouterEdge>();

// Construct graph.
// 0
// |
// =1
// |
// 2

constructEdge(graph, '0', '1');
constructEdge(graph, '1', '1');
constructEdge(graph, '1', '2');

const layouter = new SMLayouter(graph);
layouter.doLayout();

const selfEdge = graph.edge('1', '1')!;
const node = graph.get('1')!;
const lowerY = node.y + (node.height / 4);
const upperY = node.y - (node.height / 4);
const leftX = node.x - ((node.width / 2) + BACKEDGE_SPACING);
const rightX = node.x - (node.width / 2);
expect(selfEdge.points.length).toBe(4);
expect(selfEdge.points[0].x).toBeCloseTo(rightX);
expect(selfEdge.points[0].y).toBeCloseTo(lowerY);
expect(selfEdge.points[1].x).toBeCloseTo(leftX);
expect(selfEdge.points[1].y).toBeCloseTo(lowerY);
expect(selfEdge.points[2].x).toBeCloseTo(leftX);
expect(selfEdge.points[2].y).toBeCloseTo(upperY);
expect(selfEdge.points[3].x).toBeCloseTo(rightX);
expect(selfEdge.points[3].y).toBeCloseTo(upperY);
}

describe('Test vertical state machine edge routing', () => {
test('Test routing a self edge loop', testEdgeRoutingSelfLoop);
});

0 comments on commit 3c35584

Please sign in to comment.