use of org.knime.workbench.ui.layout.Graph.Node in project knime-core by knime.
the class SimpleLayouter method doLayout.
public void doLayout(final Graph g) throws RuntimeException {
double x = 1;
double y = 50;
Node start = null;
for (Node n : g.nodes()) {
if (!n.inEdges().hasNext()) {
start = n;
break;
}
}
if (start == null) {
throw new RuntimeException("No start node found");
}
y = g.getY(start);
while (start != null) {
System.out.println("Node " + start + ": " + x + ", " + y);
g.setCoordinates(start, x, y);
x += NodeContainerFigure.WIDTH * 1.5;
if (start.outEdges().hasNext()) {
start = start.outEdges().next().target();
} else {
start = null;
}
}
}
use of org.knime.workbench.ui.layout.Graph.Node in project knime-core by knime.
the class CrossingMinimizer method greedySwitch.
/**
* perform a greedy switch going from first to last layer. In each layer,
* switch consecutive nodes if crossing number is reduced. Fixed layers are
* excluded by given offsets.
*
* @param sourceOffset
* @param sinkOffset
*/
private void greedySwitch(final int sourceOffset, final int sinkOffset) {
for (int i = sourceOffset; i < m_layers.size() - sinkOffset; i++) {
ArrayList<Node> curLayer = m_layers.get(i);
int oldCross = Integer.MAX_VALUE;
int cross = numberOfCrossingsPrevLayer(i);
int crossTemp = cross;
do {
for (int j = 0; j < curLayer.size() - 1; j++) {
Node u = curLayer.get(j);
Node v = curLayer.get(j + 1);
switchNodes(u, v, curLayer, j);
// if switch produces less crossings keep it
// i.e., if switch produces equal or more crossings, switch
// back
int c = numberOfCrossingsPrevLayer(i);
if (c >= crossTemp) {
switchNodes(v, u, curLayer, j);
} else {
// crossing number is reduced -> store new crossing
// number
crossTemp = c;
}
}
oldCross = cross;
cross = numberOfCrossingsPrevLayer(i);
} while (cross < oldCross);
Collections.sort(curLayer, new Util.NodeByYComparator(m_g));
}
}
use of org.knime.workbench.ui.layout.Graph.Node in project knime-core by knime.
the class CrossingMinimizer method orderByMedian.
/**
* order the current layer by means of the average median of neighbors of
* each node in the previous layer.
*
* @param curLayer
* @param prevLayer
*/
private void orderByMedian(final ArrayList<Node> curLayer, final ArrayList<Node> prevLayer) {
for (Node v : curLayer) {
// get sorted list of neighbors in the previous layer
ArrayList<Node> neighbors = getNeighbors(v, prevLayer);
Collections.sort(neighbors, new Util.NodeByYComparator(m_g));
// set median position, or average of two medians if degree is even
int size = neighbors.size();
int m1 = (int) Math.ceil(size / 2.0) - 1;
// needed for even degree
int m2 = m1 + 1;
if (size > 0) {
// average median heuristic
if (size % 2 == 1) {
// odd degree
m_g.setY(v, m_g.getY(neighbors.get(m1)));
} else {
// even degree
double y1 = m_g.getY(neighbors.get(m1));
double y2 = m_g.getY(neighbors.get(m2));
m_g.setY(v, (y1 + y2) / 2);
}
}
}
// sort current layer by medians
Collections.sort(curLayer, new LayerSortComparator(prevLayer));
// set corresponding y-coordinates
updateY(curLayer);
}
use of org.knime.workbench.ui.layout.Graph.Node in project knime-core by knime.
the class CrossingMinimizer method copyLayering.
/**
* copies the current layering.
*
* @return
*/
private ArrayList<ArrayList<Node>> copyLayering() {
ArrayList<ArrayList<Node>> layers = new ArrayList<ArrayList<Node>>();
for (ArrayList<Node> layer : m_layers) {
ArrayList<Node> layerCopy = new ArrayList<Graph.Node>();
layers.add(layerCopy);
for (Node n : layer) {
layerCopy.add(n);
}
}
return layers;
}
use of org.knime.workbench.ui.layout.Graph.Node 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();
}
Aggregations