0

Basically, I have a game that has a big map existing out of 116 territories. Each territory has a name, some other properties and also an associated String[] with the names of its neighbour. Not every territory is connected to eachother ( I think a territory has atleast 1 connection and at most 9 connections).

So, drawing the territories like a graph should result in a planar graph. I tried using the JUNG library (as adviced on this site and on others) to do so, but every layout-algorithm they have just results in a graph that has a lot of crossing edges, which is exactly what I want to avoid. Below my code (once again the Territory class has a name property and a String[] of its neighbours' names. The map passed into the method has as key the name of the territory).

So my question is: is there a layout algoritm I can use to draw a planar graph from the territory map? Another library I should use? A tutorial I could follow? Thanks in advance guys!

public static void drawMap(Map<String, Territory> allTerritories) {
    // TODO Auto-generated constructor stub
    DirectedSparseGraph<String, String> g = new DirectedSparseGraph<>();

    Game game = new Game();
    int counter = 0;
    for (Territory t : allTerritories.values()) {
        g.addVertex(t.getName() + "(" + game.getID(t.getColor()) + ")");
        for (String s : t.getNeighbours()) {
            Territory neighbour = allTerritories.get(s);
            g.addEdge("Edge" + counter, t.getName() + "(" + game.getID(t.getColor()) + ")",
                    s + "(" + game.getID(neighbour.getColor()) + ")");
            counter++;
        }
    }

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    int width = screenSize.width;
    int height = screenSize.height;
    // KKLayout does a sort of good job

    CircleLayout<String, String> layout = new CircleLayout<String, String>(g);
    VisualizationImageServer<String, String> vv = new VisualizationImageServer<String, String>(layout,
            new Dimension(width, height));

    Function<String, String> transformer = new Function<String, String>() {
        @Override
        public String apply(String arg0) {
            if (arg0.contains("-1")) {
                String noNumber = arg0.replace(arg0.substring(arg0.length() - 4), "");
                return noNumber;
            } else {
                String noNumber = arg0.replace(arg0.substring(arg0.length() - 3), "");
                return noNumber;
            }

        }
    };
    vv.getRenderContext().setVertexLabelTransformer((Function<? super String, String>) transformer);

    vv.getRenderer().setVertexRenderer(new MyRenderer());

    // The following code adds capability for mouse picking of
    // vertices/edges. Vertices can even be moved!

    JFrame frame = new JFrame();
    frame.getContentPane().add(vv);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
}'

(Using the JUNG library, list of my imports:

import edu.uci.ics.jung.algorithms.layout.CircleLayout;
import edu.uci.ics.jung.algorithms.layout.ISOMLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.VisualizationImageServer;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.geom.Point2D;
import java.util.Map;

import javax.swing.JFrame;

The game.getID() method is a method I wrote in another class to convert a color (associated with a territory, its either gray, orange, magenta or blue) into an integer. The vertexes should also be in that color, which my code actually accomplishes!

I tried using the following layouts: KKLayout, FRLayout, SpringLayout, ISOMLayout, CircleLayout.

Sam Liemburg
  • 11
  • 1
  • 4

1 Answers1

0

There are two cases here:

  1. you have an actual (geographical) map of your 115 territories, or
  2. you just have the border relationships between them (that is, all you know is which territories border which other ones).

In case 1, you can base the layout on the locations of the territories: pick a point for each territory, create a node with that position. You can specify known node locations using StaticLayout. There's an example of this in WorldMapGraphDemo.

In case 2, depending on how the graph was generated, you may not actually know for sure that it's planar; you haven't indicated how you know that. If you aren't certain, you can test it with one of these algorithms: https://en.wikipedia.org/wiki/Planarity_testing

If you find that the graph really is planar, and the JUNG layout algorithms aren't helping you, I don't have any immediate suggestions. Avoiding edge crossings in graph layouts is in general an NP-hard problem, and none of those algorithms tries to tackle it directly.

Joshua O'Madadhain
  • 2,704
  • 1
  • 14
  • 18