diff --git a/src/main/java/ee/ut/dendroloj/Dendrologist.java b/src/main/java/ee/ut/dendroloj/Dendrologist.java index db4e115..c8d3c3f 100644 --- a/src/main/java/ee/ut/dendroloj/Dendrologist.java +++ b/src/main/java/ee/ut/dendroloj/Dendrologist.java @@ -173,7 +173,7 @@ public static void drawGraph(int[][] adjacencyMatrix, String[] labels) { * EXPERIMENTAL API *

* Draws a graph based on the provided adjacency matrix. - * Infinite values and NaN in the adjacency matrix are treated as missing edges. + * Infinite and NaN values in the adjacency matrix are treated as missing edges. * * @param adjacencyMatrix graph adjacency matrix; value at [i][j] is treated as the weight of the edge from vertex i to vertex j * @param labels string labels for vertices; pass null to use vertex indices as labels @@ -199,7 +199,7 @@ public static void drawGraph(double[][] adjacencyMatrix, String[] labels) { * EXPERIMENTAL API *

* Draws a graph based on the provided adjacency matrix. - * Infinite values and NaN in the adjacency matrix are treated as missing edges. + * Infinite and NaN values in the adjacency matrix are treated as missing edges. * * @param adjacencyMatrix graph adjacency matrix; value at [i][j] is treated as the weight of the edge from vertex i to vertex j * @param labels string labels for vertices; pass null to use vertex indices as labels diff --git a/src/main/java/ee/ut/dendroloj/GenericGraphLayout.java b/src/main/java/ee/ut/dendroloj/GenericGraphLayout.java index a489396..cd0965b 100644 --- a/src/main/java/ee/ut/dendroloj/GenericGraphLayout.java +++ b/src/main/java/ee/ut/dendroloj/GenericGraphLayout.java @@ -18,6 +18,11 @@ public static Graph assembleGraph(GraphCanvas graphCanvas) { for (var vertex : graphCanvas.vertices) { Node node = graph.addNode(IdHelper.getNodeId(vertex.vertex)); node.setAttribute("label", vertex.label); + if (vertex.fixed) { + node.setAttribute("layout._fixed"); + node.setAttribute("layout.frozen"); + node.setAttribute("xy", vertex.x, vertex.y); + } if (vertex.color != null) node.setAttribute("ui.color", vertex.color); } for (var edge : graphCanvas.edges) { diff --git a/src/main/java/ee/ut/dendroloj/GraphCanvas.java b/src/main/java/ee/ut/dendroloj/GraphCanvas.java index 95bbd91..f87f089 100644 --- a/src/main/java/ee/ut/dendroloj/GraphCanvas.java +++ b/src/main/java/ee/ut/dendroloj/GraphCanvas.java @@ -2,7 +2,9 @@ import java.awt.*; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * EXPERIMENTAL API @@ -14,21 +16,52 @@ */ public final class GraphCanvas { + private final Set drawnVertices = new HashSet<>(); final List> vertices = new ArrayList<>(); final List> edges = new ArrayList<>(); - public void drawVertex(V vertex) { - if (vertex == null) throw new NullPointerException("Vertex must not be null"); - drawVertex(vertex, vertex.toString(), null); - } + // TODO: Add overload that allows drawing a vertex with the vertex itself as a default label. + // Note that this will make the order of parameters for drawFixedVertex a little awkward. + // Also note that the default label being the vertex itself converted to a string + // might be non-obvious for reference types (especially ones that don't override toString). + + // public void drawVertex(V vertex) { + // if (vertex == null) throw new NullPointerException("Vertex must not be null"); + // drawVertex(vertex, vertex.toString(), null); + // } public void drawVertex(V vertex, String label) { - drawVertex(vertex, label, null); + if (vertex == null) throw new NullPointerException("Vertex must not be null"); + addVertex(new Vertex<>(vertex, label, null)); } public void drawVertex(V vertex, String label, Color color) { if (vertex == null) throw new NullPointerException("Vertex must not be null"); - vertices.add(new Vertex<>(vertex, label, color)); + addVertex(new Vertex<>(vertex, label, color)); + } + + // public void drawFixedVertex(V vertex, double x, double y) { + // if (vertex == null) throw new NullPointerException("Vertex must not be null"); + // drawVertex(vertex, vertex.toString(), null); + // } + + public void drawFixedVertex(V vertex, String label, double x, double y) { + if (vertex == null) throw new NullPointerException("Vertex must not be null"); + addVertex(new Vertex<>(vertex, label, null, x, y)); + } + + public void drawFixedVertex(V vertex, String label, double x, double y, Color color) { + if (vertex == null) throw new NullPointerException("Vertex must not be null"); + addVertex(new Vertex<>(vertex, label, color, x, y)); + } + + private void addVertex(Vertex vertex) { + String id = IdHelper.getNodeId(vertex.vertex); + if (drawnVertices.contains(id)) { + throw new IllegalArgumentException("Vertex " + vertex.vertex + " (" + vertex.label + ") has already been drawn"); + } + drawnVertices.add(id); + vertices.add(vertex); } /** @@ -79,11 +112,26 @@ static final class Vertex { public final T vertex; public final String label; public final Color color; + public final boolean fixed; + public final double x; + public final double y; private Vertex(T vertex, String label, Color color) { this.vertex = vertex; this.label = label; this.color = color; + this.fixed = false; + this.x = 0.0; + this.y = 0.0; + } + + private Vertex(T vertex, String label, Color color, double x, double y) { + this.vertex = vertex; + this.label = label; + this.color = color; + this.fixed = true; + this.x = x; + this.y = y; } } diff --git a/src/main/java/ee/ut/dendroloj/GraphGUI.java b/src/main/java/ee/ut/dendroloj/GraphGUI.java index c4c0247..a2af2a7 100644 --- a/src/main/java/ee/ut/dendroloj/GraphGUI.java +++ b/src/main/java/ee/ut/dendroloj/GraphGUI.java @@ -3,6 +3,7 @@ import org.graphstream.graph.Graph; import org.graphstream.ui.geom.Point2; import org.graphstream.ui.geom.Point3; +import org.graphstream.ui.graphicGraph.GraphicElement; import org.graphstream.ui.graphicGraph.GraphicGraph; import org.graphstream.ui.layout.Layout; import org.graphstream.ui.swing_viewer.SwingViewer; @@ -128,6 +129,16 @@ public void mouseDragged(MouseEvent event) { } } } + + @Override + protected void mouseButtonReleaseOffElement(GraphicElement element, MouseEvent event) { + if (!element.hasAttribute("layout._fixed")) { + view.freezeElement(element, false); + } + if (event.getButton() != 3) { + element.removeAttribute("ui.clicked"); + } + } }; view.setMouseManager(restrictedDefaultMouseManager); diff --git a/src/test/java/GraafKatsed.java b/src/test/java/GraafKatsed.java index a8a6ca8..27a6b02 100644 --- a/src/test/java/GraafKatsed.java +++ b/src/test/java/GraafKatsed.java @@ -26,11 +26,11 @@ public static void main(String[] args) { // Dendrologist.drawGraph(M, null); List tipud = new ArrayList<>(); - tipud.add(new Tipp("A")); - tipud.add(new Tipp("B")); - tipud.add(new Tipp("C")); - tipud.add(new Tipp("D")); - tipud.add(new Tipp("E")); + tipud.add(new Tipp("A", 1, 0)); + tipud.add(new Tipp("B", 2, 5)); + tipud.add(new Tipp("C", 0, 1)); + tipud.add(new Tipp("D", 1, 1)); + tipud.add(new Tipp("E", 0, 0)); tipud.get(0).kaared.add(new Kaar(11, tipud.get(1))); tipud.get(0).kaared.add(new Kaar(22, tipud.get(2))); @@ -40,9 +40,9 @@ public static void main(String[] args) { GraphCanvas lõuend = new GraphCanvas<>(); for (Tipp tipp : tipud) { - lõuend.drawVertex(tipp, tipp.tähis, Color.GREEN); + 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), Color.MAGENTA); + lõuend.drawEdge(tipp, kaar.lõppTipp, String.valueOf(kaar.kaal)); } } Dendrologist.drawGraph(lõuend); @@ -50,10 +50,14 @@ public static void main(String[] args) { private static class Tipp { public final String tähis; + public final double x; + public final double y; public final List kaared; - public Tipp(String tähis) { + public Tipp(String tähis, double x, double y) { this.tähis = tähis; + this.x = x; + this.y = y; this.kaared = new ArrayList<>(); } }