use of org.eclipse.elk.alg.common.networksimplex.NNode in project elk by eclipse.
the class NetworkSimplexLayerer method initialize.
/**
* Helper method for the network simplex layerer. It instantiates all necessary attributes for
* the execution of the network simplex layerer and initializes them with their default values.
* All edges in the connected component given by the input argument will be determined, as well
* as the number of incoming and outgoing edges of each node ( {@code inDegree}, respectively
* {@code outDegree}). All sinks and source nodes in the connected component identified in this
* step will be added to {@code sinks}, respectively {@code sources}.
*
* @param theNodes
* a {@code Collection} containing all nodes of the graph
*/
private NGraph initialize(final List<LNode> theNodes) {
final Map<LNode, NNode> nodeMap = Maps.newHashMap();
// transform nodes
NGraph graph = new NGraph();
for (LNode lNode : theNodes) {
NNode nNode = NNode.of().origin(lNode).create(graph);
nodeMap.put(lNode, nNode);
}
// transform edges
for (LNode lNode : theNodes) {
for (LEdge lEdge : lNode.getOutgoingEdges()) {
// ignore self-loops
if (lEdge.isSelfLoop()) {
continue;
}
NEdge.of(lEdge).weight(1 * Math.max(1, lEdge.getProperty(LayeredOptions.PRIORITY_SHORTNESS))).delta(1).source(nodeMap.get(lEdge.getSource().getNode())).target(nodeMap.get(lEdge.getTarget().getNode())).create();
}
}
return graph;
}
use of org.eclipse.elk.alg.common.networksimplex.NNode in project elk by eclipse.
the class NetworkSimplexLayerer method process.
/**
* The main method of the network simplex layerer. It determines an optimal layering of all
* nodes in the graph concerning a minimal length of all edges by using the network simplex
* algorithm described in {@literal Emden R. Gansner, Eleftherios Koutsofios, Stephen
* C. North, Kiem-Phong Vo: "A Technique for Drawing Directed Graphs", AT&T Bell Laboratories.
* Note that the execution time of this implemented algorithm has not been proven quadratic yet.
*
* @param theLayeredGraph
* a layered graph which initially only contains layerless nodes and is
* then filled with layers
* @param monitor
* the progress monitor
*/
public void process(final LGraph theLayeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Network simplex layering", 1);
layeredGraph = theLayeredGraph;
int thoroughness = theLayeredGraph.getProperty(LayeredOptions.THOROUGHNESS) * ITER_LIMIT_FACTOR;
List<LNode> theNodes = layeredGraph.getLayerlessNodes();
if (theNodes.size() < 1) {
monitor.done();
return;
}
// layer graph, each connected component separately
List<List<LNode>> connectedComponents = connectedComponents(theNodes);
int[] previousLayeringNodeCounts = null;
for (List<LNode> connComp : connectedComponents) {
// determine a limit on the number of iterations
int iterLimit = thoroughness * (int) Math.sqrt(connComp.size());
NGraph graph = initialize(connComp);
// execute the network simplex algorithm on the (sub-)graph
NetworkSimplex.forGraph(graph).withIterationLimit(iterLimit).withPreviousLayering(previousLayeringNodeCounts).withBalancing(true).execute(monitor.subTask(1));
// the layers are store in the NNode's layer field.
List<Layer> layers = layeredGraph.getLayers();
for (NNode nNode : graph.nodes) {
// add additional layers to match required number
while (layers.size() <= nNode.layer) {
layers.add(layers.size(), new Layer(layeredGraph));
}
LNode lNode = (LNode) nNode.origin;
lNode.setLayer(layers.get(nNode.layer));
}
if (connectedComponents.size() > 1) {
previousLayeringNodeCounts = new int[layeredGraph.getLayers().size()];
int layerIdx = 0;
for (Layer l : layeredGraph) {
previousLayeringNodeCounts[layerIdx++] = l.getNodes().size();
}
}
}
// empty the list of unlayered nodes
theNodes.clear();
// release the created resources
dispose();
monitor.done();
}
use of org.eclipse.elk.alg.common.networksimplex.NNode in project elk by eclipse.
the class NetworkSimplexPlacer method applyPositions.
// ------------------------------------------------------------------------------------------------
// Apply Layout
// ------------------------------------------------------------------------------------------------
private void applyPositions() {
for (Layer l : lGraph) {
for (LNode lNode : l) {
// find the node's corners
NodeRep nodeRep = nodeReps[lNode.id];
double minY = nodeRep.head.layer;
double maxY = nodeRep.tail.layer;
// set new position and size
lNode.getPosition().y = minY;
double sizeDelta = (maxY - minY) - lNode.getSize().y;
boolean flexibleNode = isFlexibleNode(lNode);
NodeFlexibility nf = getNodeFlexibility(lNode);
// modify the size?
if (flexibleNode && nf.isFlexibleSizeWhereSpacePermits()) {
lNode.getSize().y += sizeDelta;
}
// reposition ports if allowed
if (flexibleNode && nf.isFlexiblePorts()) {
for (LPort p : lNode.getPorts()) {
if (PortSide.SIDES_EAST_WEST.contains(p.getSide())) {
NNode nNode = portMap.get(p);
p.getPosition().y = nNode.layer - minY;
}
}
// when the node got resized, the positions of labels and south ports have to be adjusted
for (LLabel label : lNode.getLabels()) {
adjustLabelPosition(lNode, label, sizeDelta);
}
if (nf.isFlexibleSizeWhereSpacePermits()) {
lNode.getPortSideView(PortSide.SOUTH).forEach(p -> p.getPosition().y += sizeDelta);
}
}
}
}
}
use of org.eclipse.elk.alg.common.networksimplex.NNode in project elk by eclipse.
the class NetworkSimplexPlacer method insertInLayerEdgeAuxiliaryEdges.
/**
* Insert {@link NEdge}s to keep edges connected to inverted ports short.
*/
private void insertInLayerEdgeAuxiliaryEdges() {
lGraph.getLayers().stream().flatMap(l -> l.getNodes().stream()).filter(n -> n.getType() == NodeType.NORMAL).flatMap(n -> StreamSupport.stream(n.getConnectedEdges().spliterator(), false)).filter(e -> e.isInLayerEdge()).forEach(inLayerEdge -> {
boolean srcIsDummy = inLayerEdge.getSource().getNode().getType() != NodeType.NORMAL;
LPort thePort = srcIsDummy ? inLayerEdge.getTarget() : inLayerEdge.getSource();
LNode dummyNode = inLayerEdge.getOther(thePort).getNode();
NNode portRep = portMap.get(thePort);
// head/tail doesn't matter since it's a dummy node
NNode dummyRep = nodeReps[dummyNode.id].head;
final NNode src, tgt;
if (thePort.getNode().getIndex() < dummyNode.getIndex()) {
// port --> dummy
src = portRep;
tgt = dummyRep;
} else {
// dummy --> port
src = dummyRep;
tgt = portRep;
}
NEdge.of().delta(0).weight(EDGE_WEIGHT_BASE).source(src).target(tgt).create();
});
}
use of org.eclipse.elk.alg.common.networksimplex.NNode in project elk by eclipse.
the class NetworkSimplexPlacer method transformEdge.
private void transformEdge(final LEdge lEdge) {
// a dummy node
NNode dummy = NNode.of().type("edge").create(nGraph);
// calculate port offsets
NodeRep srcRep = nodeReps[lEdge.getSource().getNode().id];
NodeRep tgtRep = nodeReps[lEdge.getTarget().getNode().id];
LPort srcPort = lEdge.getSource();
LPort tgtPort = lEdge.getTarget();
double srcOffset = srcPort.getAnchor().y;
double tgtOffset = tgtPort.getAnchor().y;
// for non-flexible nodes, ports are relative to node positions
if (!srcRep.isFlexible) {
srcOffset += srcPort.getPosition().y;
}
if (!tgtRep.isFlexible) {
tgtOffset += tgtPort.getPosition().y;
}
assert DoubleMath.fuzzyEquals(srcOffset - tgtOffset, Math.round(srcOffset - tgtOffset), EPSILON) : "Port positions must be integral";
int tgtDelta = (int) Math.max(0, srcOffset - tgtOffset);
int srcDelta = (int) Math.max(0, tgtOffset - srcOffset);
double weight = getEdgeWeight(lEdge);
// an edge to the source
NEdge left = NEdge.of(lEdge).weight(weight).delta(srcDelta).source(dummy).target(portMap.get(lEdge.getSource())).create();
// an edge to the target
NEdge right = NEdge.of(lEdge).weight(weight).delta(tgtDelta).source(dummy).target(portMap.get(lEdge.getTarget())).create();
// remember
EdgeRep edgeRep = new EdgeRep(lEdge, dummy, left, right);
edgeReps[lEdge.id] = edgeRep;
}
Aggregations