package uk.ac.rhul.cs.cl1.ui;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.concurrent.Callable;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import uk.ac.rhul.cs.graph.Edge;
import uk.ac.rhul.cs.graph.Graph;
import uk.ac.rhul.cs.graph.GraphLayoutAlgorithm;
import uk.ac.rhul.cs.graph.Layout;
/**
* Class that is responsible for rendering a graph with a given layout to
* a given drawing context.
*
* @author tamas
*/
public class GraphRenderer implements Callable<Icon> {
/** Local instance of the graph layout algorithm used in the rendering process */
GraphLayoutAlgorithm algorithm = null;
/** Node colors for the graph */
HashMap<Integer, Color> colors = null;
/** Calculated layout of the graph according to the layout algorithm */
Layout layout = null;
/**
* Constructs a renderer that will render the given graph using the given
* layout algorithm and the given color mapping
*/
public GraphRenderer(Graph graph, GraphLayoutAlgorithm algorithm, HashMap<Integer, Color> colors) {
this.algorithm = algorithm;
this.algorithm.setGraph(graph);
this.colors = colors;
}
/**
* Constructs a renderer that will render the given graph using the given
* layout algorithm and the default colors
*/
public GraphRenderer(Graph graph, GraphLayoutAlgorithm algorithm) {
this(graph, algorithm, new HashMap<Integer, Color>());
}
/**
* Calculates the layout of the graph
*/
private void calculateLayout() {
if (this.layout == null)
this.layout = this.algorithm.getResults();
}
/**
* Renders the graph to the given graphics context into the given box
*/
public void render(Graphics2D g, Rectangle2D rect) {
calculateLayout();
this.layout.fitToRectangle(rect);
Graph graph = this.algorithm.getGraph();
int n = this.layout.size();
if (graph.getNodeCount() != n) {
System.out.println("hmmm, wtf?");
return;
}
/* Draw the edges */
g.setColor(Color.BLACK);
for (Edge edge: graph) {
Point2D from = this.layout.getCoordinates(edge.source);
Point2D to = this.layout.getCoordinates(edge.target);
g.drawLine((int)from.getX(), (int)from.getY(), (int)to.getX(), (int)to.getY());
}
/* Draw the nodes */
for (int i = 0; i < n; i++) {
Point2D point = this.layout.getCoordinates(i);
Color color = colors.get(i);
if (color == null)
color = Color.RED;
g.setColor(color);
g.fillOval((int)point.getX()-2, (int)point.getY()-2, 5, 5);
}
}
/**
* Renders the graph to the given image, covering the whole area of the image
*/
public void render(BufferedImage image) {
Graphics2D g2d = image.createGraphics();
g2d.setColor(new Color(0, 0, 0, 0));
g2d.setComposite(AlphaComposite.Src);
g2d.fill(new Rectangle2D.Double(0, 0, image.getWidth(), image.getHeight()));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Rectangle2D rect = new Rectangle2D.Double(3, 3, image.getWidth() - 6, image.getHeight() - 6);
this.render(g2d, rect);
}
public Icon call() throws Exception {
BufferedImage image = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
this.render(image);
return new ImageIcon(image);
}
}