net.sf.gluebooster.java.booster.basic.math.graph.JungGraphLayouter Maven / Gradle / Ivy
package net.sf.gluebooster.java.booster.basic.math.graph;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.KeyListener;
import java.awt.geom.Point2D;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import org.apache.commons.collections4.TransformerUtils;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.StaticLayout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import net.sf.gluebooster.java.booster.basic.math.GeometryBoostUtils;
import net.sf.gluebooster.java.booster.basic.math.GeometryPositionConstraint;
import net.sf.gluebooster.java.booster.basic.transformation.CallableDelegate;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.CallableByConstant;
import net.sf.gluebooster.java.booster.essentials.logging.LogBooster;
/**
* Does a layout for jung graphs
*
* @author CBauer
*
*/
public class JungGraphLayouter /* extends BoostedObject */{
/**
* Writes logging information.
*/
private LogBooster log = new LogBooster(getClass());
/**
* The graph that is to be layouted.
*/
private Graph graph;
/**
* The configuration of the layout.
*/
private GraphDisplayConfiguration configuration;
/**
* The actual dimension of the layout
*/
private Dimension computedLayoutDimension;
// private Transformer vertexFillPaintTransformer;
// private boolean displayVertexLabel = false;
// private Transformer vertexLabelTransformer;
// private boolean displayVertexTooltip = false;
// private Transformer vertexToolTipTransformer;
// private GraphMouseListener graphMouseListener;
// private List keyListeners = new ArrayList();
// private Transformer vertexShapeTransformer;
public JungGraphLayouter() {
}
/**
* Creata a layout of the graph.
*
* @return the created layout
*/
private Layout createLayout() throws Exception {
if (configuration.getLayoutDimension() == null) {
log.info("no default layout dimension set");
// displayConfiguration.setLayoutDimension(new Dimension(300, 300));
}
computedLayoutDimension = configuration.getLayoutDimension();
// create a basic layout by using an existing layout
FRLayout layout = new FRLayout(graph);
// Layout layout = new CircleLayout(
// graph);
// TODO create the graph of the FRLayout and then modify the positions
// (by using a staticLayout) so that no overlapping occurs
layout.setSize(configuration.getLayoutDimension());
// layout.setForceMultiplier()
// layout.setRepulsionRange(300);
// layout.setRepulsionMultiplier(50);
// layout.setAttractionMultiplier(0.01);
if (configuration.getVertexShapeTransformer() == null) {
return layout;
// hopefully the layout is good enough
// nothing more needs be done yet
// Optimization: use the modification of the else part always. Use
// the default vertex shape transformer to compute the shapes of the
// vertices.
} else {
// Optimize the layout by removing overlapping vertices and edges
layout.initialize();
// Compute the shapes of the vertices
Graph graph1 = new UndirectedSparseGraph();
HashMap shapes = new HashMap();
for (Vertex vertex : graph.getVertices()) {
Point2D center = layout.apply(vertex);
Shape shape = (Shape) configuration.getVertexShapeTransformer()
.call(vertex);
Rectangle bounds = shape.getBounds();
bounds.x = (int) center.getX();
bounds.y = (int) center.getY();
shapes.put(vertex, bounds);
graph1.addVertex(bounds);
}
// compute the edges between the shapes
for (Edge edge : graph.getEdges()) {
edu.uci.ics.jung.graph.util.Pair endpoints = graph
.getEndpoints(edge);
graph1.addEdge(edge, shapes.get(endpoints.getFirst()),
shapes.get(endpoints.getSecond()));
}
// reposition the shapes to avoid overlapping
GeometryPositionConstraint constraints = new GeometryPositionConstraint();
constraints.setMinimumDistance(30);
// GeometryBoostUtils
// .repositionWithoutOverlapping(graph1, constraints);
GeometryBoostUtils.position(graph1, constraints);
// transfer the shape positions to the vertices
int maxX = 0;
int maxY = 0;
HashMap positions = new HashMap();
for (Entry entry : shapes.entrySet()) {
Rectangle position = entry.getValue();
positions.put(entry.getKey(), position.getLocation());
maxX = Math.max(maxX, position.x + position.width);
maxY = Math.max(maxY, position.y + position.height);
}
GeometryBoostUtils.checkOverlappings(graph1, configuration.getOverlappingAllowed(),
true, true, false, constraints);
// add margin
maxX = maxX + 10;
maxY = maxY + 10;
computedLayoutDimension = new Dimension(maxX, maxY);
// Vertex locations can be placed in a Map and then supplied to this
// layout as follows: Transformer vertexLocations =
// TransformerUtils.mapTransformer(map);
StaticLayout result = new StaticLayout(
graph, new CallableDelegate(TransformerUtils.mapTransformer(positions)),
computedLayoutDimension);
return result;
}
}
/**
* Creates a layout component of the graph.
*
* @return the created layout
*/
public Component createLayoutComponent() throws Exception {
// FRLayout layout = new FRLayout(graph);
// layout.setSize(layoutDimension);
Layout layout = createLayout();
// The BasicVisualizationServer is parameterized by the edge types
// BasicVisualizationServer vv = new
// BasicVisualizationServer(
// layout);
JungVisualizationViewer vv = new JungVisualizationViewer(layout);
vv.setExceptionListener(configuration.getExceptionListener());
if (configuration.isDisplayVertexLabel()) {
if (configuration.getVertexLabelTransformer() != null) {
vv.getRenderContext().setVertexLabelTransformer(
new CallableDelegate(configuration.getVertexLabelTransformer()));
} else if (configuration.getVertexToolTipTransformer() != null) {
vv.getRenderContext().setVertexLabelTransformer(
new CallableDelegate(configuration.getVertexToolTipTransformer()));
}
}
if (configuration.isDisplayVertexTooltip()) {
if (configuration.getVertexToolTipTransformer() != null) {
vv.setVertexToolTipTransformer(new CallableDelegate(configuration.getVertexToolTipTransformer()));
} else if (configuration.getVertexLabelTransformer() != null) {
vv.getRenderContext().setVertexLabelTransformer(
new CallableDelegate(configuration.getVertexLabelTransformer()));
}
}
vv.setPreferredSize(computedLayoutDimension);
if (configuration.getVertexBackgroundTransformer() != null) {
vv.getRenderContext().setVertexFillPaintTransformer(
new CallableDelegate(configuration.getVertexBackgroundTransformer()));
} else {
vv.getRenderContext().setVertexFillPaintTransformer(
new CallableDelegate(new CallableByConstant(null)));
}
if (configuration.getClickListener() != null) {
vv.addGraphMouseListener(configuration.getClickListener());
}
List listeners = configuration.getKeyListeners();
if (listeners != null) {
for (KeyListener keylistener : listeners) {
vv.addKeyListener(keylistener);
}
}
if (configuration.getVertexShapeTransformer() != null) {
vv.getRenderContext().setVertexShapeTransformer(
new CallableDelegate(configuration.getVertexShapeTransformer()));
}
if (configuration.getVertexIconTransformer() != null) {
vv.getRenderContext().setVertexIconTransformer(new CallableDelegate(configuration.getVertexIconTransformer()));
}
// vv.getRenderContext().setVertexLabelRenderer(vertexLabelRenderer);
vv.getRenderer().getVertexLabelRenderer()
.setPosition(Renderer.VertexLabel.Position.CNTR);
return vv;
// JViewport viewport = new JViewport();
// viewport.setView(vv);
// viewport.setAutoscrolls(true);
// return viewport;
}
public Graph getGraph() {
return graph;
}
public void setGraph(Graph graph) {
this.graph = graph;
}
// public Transformer getVertexFillPaintTransformer() {
// return vertexFillPaintTransformer;
// }
//
// public void setVertexFillPaintTransformer(
// Transformer vertexFillPaintTransformer) {
// this.vertexFillPaintTransformer = vertexFillPaintTransformer;
// }
// public Transformer getVertexToolTipTransformer() {
// return vertexToolTipTransformer;
// }
//
// public void setVertexToolTipTransformer(
// Transformer vertexToolTipTransformer) {
// this.vertexToolTipTransformer = vertexToolTipTransformer;
// }
// public GraphMouseListener getGraphMouseListener() {
// return graphMouseListener;
// }
//
// public void setGraphMouseListener(
// GraphMouseListener graphMouseListener) {
// this.graphMouseListener = graphMouseListener;
// }
// public List getKeyListeners() {
// return keyListeners;
// }
//
// public void setKeyListeners(List keyListeners) {
// this.keyListeners = keyListeners;
// }
//
// public void addKeyListener(KeyListener listener) {
// keyListeners.add(listener);
// }
// public Transformer getVertexShapeTransformer() {
// return vertexShapeTransformer;
// }
//
// public void setVertexShapeTransformer(
// Transformer vertexShapeTransformer) {
// this.vertexShapeTransformer = vertexShapeTransformer;
// }
//
// public Transformer getVertexLabelTransformer() {
// return vertexLabelTransformer;
// }
//
// public void setVertexLabelTransformer(
// Transformer vertexLabelTransformer) {
// this.vertexLabelTransformer = vertexLabelTransformer;
// }
//
// public boolean isDisplayVertexLabel() {
// return displayVertexLabel;
// }
//
// public void setDisplayVertexLabel(boolean displayVertexLabel) {
// this.displayVertexLabel = displayVertexLabel;
// }
//
// public boolean isDisplayVertexTooltip() {
// return displayVertexTooltip;
// }
//
// public void setDisplayVertexTooltip(boolean displayVertexTooltip) {
// this.displayVertexTooltip = displayVertexTooltip;
// }
public GraphDisplayConfiguration getConfiguration() {
return configuration;
}
public void setConfiguration(GraphDisplayConfiguration configuration) {
this.configuration = configuration;
}
}