From 4841e127ae290502ff7feef01b41ecd415a03e14 Mon Sep 17 00:00:00 2001 From: Juhan Oskar Hennoste Date: Sat, 9 Dec 2023 18:55:06 +0200 Subject: [PATCH] Add support for directed edge collapsing --- .../ee/ut/dendroloj/GenericGraphLayout.java | 2 + .../java/ee/ut/dendroloj/GraphCanvas.java | 42 +++++++++++++++++-- src/main/java/ee/ut/dendroloj/GraphGUI.java | 5 +++ .../ui/swing/renderer/shape/Connector.java | 4 +- src/test/java/GraafKatsed.java | 28 +++++++++---- 5 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/main/java/ee/ut/dendroloj/GenericGraphLayout.java b/src/main/java/ee/ut/dendroloj/GenericGraphLayout.java index b422f14..c437d68 100644 --- a/src/main/java/ee/ut/dendroloj/GenericGraphLayout.java +++ b/src/main/java/ee/ut/dendroloj/GenericGraphLayout.java @@ -40,6 +40,8 @@ public static Graph assembleGraph(GraphCanvas graphCanvas) { Edge graphEdge = graph.addEdge(IdHelper.getNewEdgeId(), v1, v2, edge.directed); if (edge.label != null) graphEdge.setAttribute("label", edge.label); if (edge.color != null) graphEdge.setAttribute("ui.color", edge.color); + if (edge.collapsed) graphEdge.setAttribute("ui._collapse"); + if (edge.arrowOnly) graphEdge.setAttribute("ui.class", "arrowonly"); } return graph; } diff --git a/src/main/java/ee/ut/dendroloj/GraphCanvas.java b/src/main/java/ee/ut/dendroloj/GraphCanvas.java index 087d5a7..6aa3388 100644 --- a/src/main/java/ee/ut/dendroloj/GraphCanvas.java +++ b/src/main/java/ee/ut/dendroloj/GraphCanvas.java @@ -1,10 +1,8 @@ package ee.ut.dendroloj; import java.awt.*; -import java.util.ArrayList; -import java.util.HashSet; +import java.util.*; import java.util.List; -import java.util.Set; /** * A helper class for drawing a graph. @@ -14,6 +12,7 @@ */ public final class GraphCanvas { + private final Map> collapsibleEdges = new HashMap<>(); private final Set drawnVertices = new HashSet<>(); final List> vertices = new ArrayList<>(); final List> edges = new ArrayList<>(); @@ -116,7 +115,40 @@ public void drawDirectedEdge(V v1, V v2, String label) { */ public void drawDirectedEdge(V v1, V v2, String label, Color color) { if (v1 == null || v2 == null) throw new NullPointerException("Target vertices must not be null"); - edges.add(new Edge<>(true, v1, v2, label, color)); + String v1id = IdHelper.getNodeId(v1); + String v2id = IdHelper.getNodeId(v2); + Edge edge = new Edge<>(true, v1, v2, label, color); + Edge collapsibleEdge = collapsibleEdges.get(new IdPair(v2id, v1id)); + edges.add(edge); + collapsibleEdges.putIfAbsent(new IdPair(v1id, v2id), edge); + if (collapsibleEdge != null && !collapsibleEdge.collapsed && Objects.equals(collapsibleEdge.label, label)) { + edge.collapsed = true; + edge.arrowOnly = true; + collapsibleEdge.collapsed = true; + } + } + + private static class IdPair { + public final String v1; + public final String v2; + + public IdPair(String v1, String v2) { + this.v1 = v1; + this.v2 = v2; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + IdPair idPair = (IdPair) o; + return Objects.equals(v1, idPair.v1) && Objects.equals(v2, idPair.v2); + } + + @Override + public int hashCode() { + return Objects.hash(v1, v2); + } } static final class Vertex { @@ -148,6 +180,8 @@ private Vertex(T vertex, String label, Color color, double x, double y) { static final class Edge { public final boolean directed; + public boolean collapsed = false; + public boolean arrowOnly = false; public final T v1; public final T v2; public final String label; diff --git a/src/main/java/ee/ut/dendroloj/GraphGUI.java b/src/main/java/ee/ut/dendroloj/GraphGUI.java index e16d6ed..4563e05 100644 --- a/src/main/java/ee/ut/dendroloj/GraphGUI.java +++ b/src/main/java/ee/ut/dendroloj/GraphGUI.java @@ -9,6 +9,7 @@ import org.graphstream.ui.swing_viewer.SwingViewer; import org.graphstream.ui.swing_viewer.util.DefaultMouseManager; import org.graphstream.ui.view.View; +import org.graphstream.ui.view.Viewer; import org.graphstream.ui.view.camera.Camera; import org.graphstream.ui.view.util.MouseManager; import org.graphstream.ui.view.util.ShortcutManager; @@ -37,6 +38,10 @@ public static void initGenericGUI(double uiScale, Graph graph, Layout layout) { "edge.error {" + " fill-color: rgb(255, 0, 0);" + "}" + + "edge.arrowonly {" + + " text-mode: hidden;"+ + " size: 0px;" + + "}" + "node {" + " size: %fpx;" + " fill-mode: dyn-plain;" + diff --git a/src/main/java/org/graphstream/ui/swing/renderer/shape/Connector.java b/src/main/java/org/graphstream/ui/swing/renderer/shape/Connector.java index 4589bc7..0503ad1 100644 --- a/src/main/java/org/graphstream/ui/swing/renderer/shape/Connector.java +++ b/src/main/java/org/graphstream/ui/swing/renderer/shape/Connector.java @@ -135,8 +135,10 @@ public void configureConnectorForElement(DefaultCamera2D camera, GraphicEdge ele if (element.hasAttribute("ui.points")) { skel.setPoly(element.getAttribute("ui.points")); } else { + // DENDROLOJ EDIT: + // Disabled multi-edge rendering for edges that are marked with ui._collapse. positionForLinesAndCurves(skel, element.from.getStyle(), element.from, - element.to, element.multi, element.getGroup()); + element.to, element.multi, element.hasAttribute("ui._collapse") ? null : element.getGroup()); } } diff --git a/src/test/java/GraafKatsed.java b/src/test/java/GraafKatsed.java index 447621e..0434f62 100644 --- a/src/test/java/GraafKatsed.java +++ b/src/test/java/GraafKatsed.java @@ -23,8 +23,18 @@ public static void main(String[] args) { {12, -1, -1, 0, -1}, {-1, -1, 5, 4, 123} }; - Dendrologist.drawGraph(M, nimed); - // Dendrologist.drawGraph(M, null); + { + GraphCanvas lõuend = new GraphCanvas<>(); + for (int i = 0; i < M.length; i++) { + lõuend.drawVertex(i, nimed[i]); + } + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (i != j && M[i][j] != - 1) lõuend.drawDirectedEdge(i, j, String.valueOf(M[i][j])); + } + } + Dendrologist.drawGraph(lõuend); + } List tipud = new ArrayList<>(); tipud.add(new Tipp("A", 1, 0)); @@ -39,14 +49,16 @@ public static void main(String[] args) { tipud.get(4).kaared.add(new Kaar(0, tipud.get(4))); tipud.get(4).kaared.add(new Kaar(7, tipud.get(2))); - GraphCanvas lõuend = new GraphCanvas<>(); - for (Tipp tipp : tipud) { - lõuend.drawFixedVertex(tipp, tipp.tähis, tipp.x, tipp.y); - for (Kaar kaar : tipp.kaared) { - lõuend.drawEdge(tipp, kaar.lõppTipp, String.valueOf(kaar.kaal)); + { + GraphCanvas lõuend = new GraphCanvas<>(); + for (Tipp tipp : tipud) { + lõuend.drawFixedVertex(tipp, tipp.tähis, tipp.x, tipp.y); + for (Kaar kaar : tipp.kaared) { + lõuend.drawEdge(tipp, kaar.lõppTipp, String.valueOf(kaar.kaal)); + } } + Dendrologist.drawGraph(lõuend); } - Dendrologist.drawGraph(lõuend); } private static class Tipp {