package net.sourceforge.jabm.report;
import java.awt.geom.Point2D;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.apache.commons.collections15.Transformer;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.UndirectedGraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.graph.util.Pair;
public class DotWriter<V, E> {
protected DecimalFormat labelFormatter = new DecimalFormat("#.00");
/**
* graph graphname { // The label attribute can be used to change the label
* of a node a [label="Foo"]; // Here, the node shape is changed. b
* [shape=box]; // These edges both have different line properties a -- b --
* c [color=blue]; b -- d [style=dotted]; }
**/
public DotWriter() {
}
/**
* Saves <code>g</code> to <code>filename</code>. Labels for vertices may be
* supplied by <code>vs</code>. Edge weights are specified by
* <code>nev</code>.
*
* @throws IOException
*/
public void save(Graph<V, E> g, String filename, Transformer<V, String> vs,
Transformer<E, Number> nev, Transformer<V, Point2D> vld)
throws IOException {
save(g, new FileWriter(filename), vs, nev, vld);
}
/**
* Saves <code>g</code> to <code>filename</code>. Labels are specified by
* <code>vs</code>, and edge weights by <code>nev</code>; vertex coordinates
* are not written out.
*
* @param g
* the graph to write out
* @param filename
* @param vs
* @param nev
* @throws IOException
*/
public void save(Graph<V, E> g, String filename, Transformer<V, String> vs,
Transformer<E, Number> nev) throws IOException {
save(g, new FileWriter(filename), vs, nev, null);
}
/**
* Saves <code>g</code> to <code>filename</code>; no vertex labels are
* written out, and the edge weights are written as 1.0.
*
* @throws IOException
*/
public void save(Graph<V, E> g, String filename) throws IOException {
save(g, filename, null, null, null);
}
/**
* Saves <code>g</code> to <code>w</code>; no vertex labels are written out,
* and the edge weights are written as 1.0.
*
* @throws IOException
*/
public void save(Graph<V, E> g, Writer w) throws IOException {
save(g, w, null, null, null);
}
/**
* Saves <code>g</code> to <code>w</code>; vertex labels are given by
* <code>vs</code> and edge weights by <code>nev</code>.
*
* @param g
* @param w
* @param vs
* @param nev
* @throws IOException
*/
public void save(Graph<V, E> g, Writer w, Transformer<V, String> vs,
Transformer<E, Number> nev) throws IOException {
save(g, w, vs, nev, null);
}
/**
* Writes <code>graph</code> to <code>w</code>. Labels for vertices may be
* supplied by <code>vs</code> (defaults to no labels if null), edge weights
* may be specified by <code>nev</code> (defaults to weights of 1.0 if
* null), and vertex locations may be specified by <code>vld</code>
* (defaults to no locations if null).
*/
public void save(Graph<V, E> graph, Writer w, Transformer<V, String> vs,
Transformer<E, Number> nev, Transformer<V, Point2D> vld)
throws IOException {
BufferedWriter writer = new BufferedWriter(w);
if (nev == null)
nev = new Transformer<E, Number>() {
public Number transform(E e) {
return 1;
}
};
// writer.write("*Vertices " + graph.getVertexCount());
// writer.newLine();
List<V> id = new ArrayList<V>(graph.getVertices());// Indexer.getIndexer(graph);
//
Collection<E> d_set = new HashSet<E>();
Collection<E> u_set = new HashSet<E>();
boolean directed = graph instanceof DirectedGraph;
boolean undirected = graph instanceof UndirectedGraph;
String graphName = "jung" + graph.hashCode();
// if it's strictly one or the other, no need to create extra sets
if (directed) {
d_set.addAll(graph.getEdges());
writer.write("digraph ");
}
if (undirected) {
u_set.addAll(graph.getEdges());
writer.write("graph ");
}
if (!directed && !undirected) // mixed-mode graph
{
writer.write("digraph ");
u_set.addAll(graph.getEdges());
d_set.addAll(graph.getEdges());
for (E e : graph.getEdges()) {
if (graph.getEdgeType(e) == EdgeType.UNDIRECTED) {
d_set.remove(e);
} else {
u_set.remove(e);
}
}
}
writer.write(graphName + " {");
writer.newLine();
for (V currentVertex : graph.getVertices()) {
// convert from 0-based to 1-based index
int v_id = id.indexOf(currentVertex) + 1;
writer.write("" + v_id + " [");
if (vs != null) {
String label = vs.transform(currentVertex);
if (label != null) {
writer.write("label = \"" + label + "\"");
}
}
// if (vld != null) {
// Point2D location = vld.transform(currentVertex);
// if (location != null)
// writer.write(" " + location.getX() + " " + location.getY()
// + " 0.0");
// }
// writer.write("fontsize=6");
// writer.write(",height=" +nodeHeight + ",width=" + nodeWidth);
// writer.write(",shape=circle");
writer.write("]");
writer.newLine();
}
// write out directed edges
// if (!d_set.isEmpty()) {
// writer.write("*Arcs");
// writer.newLine();
// }
for (E e : d_set) {
int source_id = id.indexOf(graph.getEndpoints(e).getFirst()) + 1;
int target_id = id.indexOf(graph.getEndpoints(e).getSecond()) + 1;
float weight = nev.transform(e).floatValue();
String label = labelFormatter.format(weight);
writer.write(" " + source_id + " -> " + target_id + " [label=\""
+ label + "\"]");
writer.newLine();
}
// write out undirected edges
// if (!u_set.isEmpty()) {
// writer.write("*Edges");
// writer.newLine();
// }
for (E e : u_set) {
Pair<V> endpoints = graph.getEndpoints(e);
int v1_id = id.indexOf(endpoints.getFirst()) + 1;
int v2_id = id.indexOf(endpoints.getSecond()) + 1;
float weight = nev.transform(e).floatValue();
String label = labelFormatter.format(weight);
writer.write(v1_id + " -- " + v2_id + " [label=\"" + label + "\"]");
writer.newLine();
}
writer.write("}");
writer.newLine();
writer.close();
}
}