use of org.knime.workbench.ui.layout.Graph in project knime-core by knime.
the class SimpleLayeredLayouter method doLayout.
/**
* computes an hierarchical layout of the given graph. If nodes are fixed by
* means of the given map, they will end up on the first or last layer,
* ordered by their original y-coordinate. Precondition: g must be a
* directed acyclic graph!
*
* @param g the graph to perform layout on
* @param fixedNodes node map containing true if the respective node should
* be fixed (only sources and sinks allowed)
* @throws RuntimeException
*/
public void doLayout(final Graph g, final Map<Node, Boolean> fixedNodes) throws RuntimeException {
// create lists for fixed sources and sinks if necessary
ArrayList<Node> fixedSources = null;
ArrayList<Node> fixedSinks = null;
if (fixedNodes != null) {
fixedSources = new ArrayList<Graph.Node>();
fixedSinks = new ArrayList<Graph.Node>();
for (Node n : g.nodes()) {
if (fixedNodes.get(n)) {
if (n.inDegree() == 0) {
fixedSources.add(n);
} else if (n.outDegree() == 0) {
fixedSinks.add(n);
}
}
}
if (fixedSources.isEmpty()) {
fixedSources = null;
}
if (fixedSinks.isEmpty()) {
fixedSinks = null;
}
}
// get layering of the graph
Map<Node, Integer> nodeLayer = g.createIntNodeMap();
ArrayList<ArrayList<Node>> layers = Layerer.assignLayers(g, nodeLayer, fixedSources, fixedSinks);
// add dummy vertices for edges spanning several layers
ArrayList<Edge> hiddenEdges = new ArrayList<Graph.Edge>();
ArrayList<Node> dummyNodes = new ArrayList<Graph.Node>();
ArrayList<Edge> dummyEdges = new ArrayList<Graph.Edge>();
HashMap<Edge, ArrayList<Node>> hiddenEdgeToDummyVertices = new HashMap<Graph.Edge, ArrayList<Node>>();
for (Edge e : g.edges()) {
int startLayer = nodeLayer.get(e.source()).intValue();
int endLayer = nodeLayer.get(e.target()).intValue();
int span = endLayer - startLayer;
if (span > 1) {
hiddenEdges.add(e);
}
}
// concurrent modification due to iterator
for (Edge e : hiddenEdges) {
// list for this edges dummy nodes
ArrayList<Node> eDummyNodes = new ArrayList<Graph.Node>();
int startLayer = nodeLayer.get(e.source()).intValue();
int endLayer = nodeLayer.get(e.target()).intValue();
int span = endLayer - startLayer;
Node last = e.source();
for (int i = 1; i < span; i++) {
Node current = g.createNode("bend " + e + ", " + i, startLayer + i, g.getY(last));
// add dummy to its layer
nodeLayer.put(current, startLayer + i);
layers.get(startLayer + i).add(current);
// add dummy edge to graph
Edge dEdge = g.createEdge(last, current);
dummyEdges.add(dEdge);
// add dummy vertex to the list of dummies for the original edge
eDummyNodes.add(current);
// proceed
last = current;
}
// add last dummy edge
g.createEdge(last, e.target());
// store list of dummy nodes for original edge
hiddenEdgeToDummyVertices.put(e, eDummyNodes);
// add this edges dummy Nodes to the list of all dummy nodes
dummyNodes.addAll(eDummyNodes);
}
// remove hidden edges
for (Edge e : hiddenEdges) {
g.removeEdge(e);
}
// set initial coordinates by layer
int layer = 0;
for (ArrayList<Node> currentLayer : layers) {
// sort first and last layer by y-coordinate if fixed
if (layer == 0 && fixedSources != null) {
Collections.sort(currentLayer, new Util.NodeByYComparator(g));
} else if (layer == layers.size() - 1 && fixedSinks != null) {
Collections.sort(currentLayer, new Util.NodeByYComparator(g));
} else {
// here the ordering is shuffled, could also be done several
// times in the crossing minimization phase.
// I.e., every execution of the algorithm potentially yields
// another result!
Collections.shuffle(currentLayer, m_rnd);
// ordering could also be initialized by the current ordering
// from y-coordinates.
// Collections.sort(currentLayer, new
// Util.NodeByYComparator(g));
}
// set coordinates from 0,1,...,size of layer
int verticalCoord = 0;
for (Node n : currentLayer) {
g.setCoordinates(n, layer, verticalCoord);
verticalCoord++;
}
layer++;
}
/* Do crossing minimization */
CrossingMinimizer cm = new CrossingMinimizer(g, layers, fixedSources, fixedSinks);
cm.run();
/* Do vertical placement */
VerticalCoordinateAssigner vca = new VerticalCoordinateAssigner(g, layers, dummyNodes, dummyEdges);
vca.setBalanceBranchings(m_balanceBranching);
vca.run();
/*
* Reinsert hidden edges with bendpoints, and remove dummy nodes and
* edges
*/
for (Edge hEdge : hiddenEdges) {
Edge e = g.reinsert(hEdge);
for (Node n : hiddenEdgeToDummyVertices.get(hEdge)) {
g.addBend(e, g.getX(n), g.getY(n));
// also removes dummy edges!
g.removeNode(n);
}
}
// clean up unnecessary bend-points
g.cleanBends();
}