use of org.eclipse.elk.alg.layered.graph.LNode in project elk by eclipse.
the class HighDegreeNodeLayeringProcessor method process.
@Override
public void process(final LGraph graph, final IElkProgressMonitor progressMonitor) {
this.layeredGraph = graph;
// retrieve some properties
degreeThreshold = graph.getProperty(LayeredOptions.HIGH_DEGREE_NODES_THRESHOLD);
treeHeightThreshold = graph.getProperty(LayeredOptions.HIGH_DEGREE_NODES_TREE_HEIGHT);
// translate 0 to 'arbitrary height'
if (treeHeightThreshold == 0) {
treeHeightThreshold = Integer.MAX_VALUE;
}
// now iterate through all layer
final ListIterator<Layer> layerIt = graph.getLayers().listIterator();
while (layerIt.hasNext()) {
Layer lay = layerIt.next();
// -----------------------------------------------------------------------
// #1 find high degree nodes and find their incoming and outgoing trees
// -----------------------------------------------------------------------
List<Pair<LNode, HighDegreeNodeInformation>> highDegreeNodes = Lists.newArrayList();
int incMax = -1;
int outMax = -1;
for (LNode n : lay.getNodes()) {
if (isHighDegreeNode(n)) {
HighDegreeNodeInformation hdni = calculateInformation(n);
incMax = Math.max(incMax, hdni.incTreesMaxHeight);
outMax = Math.max(outMax, hdni.outTreesMaxHeight);
highDegreeNodes.add(Pair.of(n, hdni));
}
}
// -----------------------------------------------------------------------
// #2 insert layers before the current layer and move the trees
// -----------------------------------------------------------------------
List<Layer> preLayers = Lists.newArrayList();
for (int i = 0; i < incMax; ++i) {
preLayers.add(0, prependLayer(layerIt));
}
for (Pair<LNode, HighDegreeNodeInformation> highDegreeNode : highDegreeNodes) {
List<LNode> incRoots = highDegreeNode.getSecond().incTreeRoots;
if (incRoots == null) {
continue;
}
for (LNode incRoot : incRoots) {
moveTree(incRoot, INCOMING_EDGES, preLayers);
}
}
// -----------------------------------------------------------------------
// #2 insert layers after the current layer and move the trees
// -----------------------------------------------------------------------
List<Layer> afterLayers = Lists.newArrayList();
for (int i = 0; i < outMax; ++i) {
afterLayers.add(appendLayer(layerIt));
}
for (Pair<LNode, HighDegreeNodeInformation> highDegreeNode : highDegreeNodes) {
List<LNode> outRoots = highDegreeNode.getSecond().outTreeRoots;
if (outRoots == null) {
continue;
}
for (LNode outRoot : outRoots) {
moveTree(outRoot, OUTGOING_EDGES, afterLayers);
}
}
}
// -----------------------------------------------------------------------
// #2 it can happen that layers became empty
// after the previous processing, remove them
// -----------------------------------------------------------------------
ListIterator<Layer> layerIt2 = graph.getLayers().listIterator();
while (layerIt2.hasNext()) {
Layer l = layerIt2.next();
if (l.getNodes().isEmpty()) {
layerIt2.remove();
}
}
}
use of org.eclipse.elk.alg.layered.graph.LNode in project elk by eclipse.
the class InvertedPortProcessor method createEastPortSideDummies.
/**
* Creates the necessary dummy nodes for an input port on the east side of a node, provided that
* the edge connects two different nodes.
*
* @param layeredGraph
* the layered graph.
* @param eastwardPort
* the offending port.
* @param edge
* the edge connected to the port.
* @param layerNodeList
* list of unassigned nodes belonging to the layer of the node the port belongs to.
* The new dummy node is added to this list and must be assigned to the layer later.
*/
private void createEastPortSideDummies(final LGraph layeredGraph, final LPort eastwardPort, final LEdge edge, final List<LNode> layerNodeList) {
assert edge.getTarget() == eastwardPort;
// Ignore self loops
if (edge.getSource().getNode() == eastwardPort.getNode()) {
return;
}
// Dummy node in the same layer
LNode dummy = new LNode(layeredGraph);
dummy.setType(NodeType.LONG_EDGE);
dummy.setProperty(InternalProperties.ORIGIN, edge);
dummy.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS);
layerNodeList.add(dummy);
LPort dummyInput = new LPort();
dummyInput.setNode(dummy);
dummyInput.setSide(PortSide.WEST);
LPort dummyOutput = new LPort();
dummyOutput.setNode(dummy);
dummyOutput.setSide(PortSide.EAST);
// Reroute the original edge
edge.setTarget(dummyInput);
// Connect the dummy with the original port
LEdge dummyEdge = new LEdge();
dummyEdge.copyProperties(edge);
dummyEdge.setProperty(LayeredOptions.JUNCTION_POINTS, null);
dummyEdge.setSource(dummyOutput);
dummyEdge.setTarget(eastwardPort);
// Set LONG_EDGE_SOURCE and LONG_EDGE_TARGET properties on the LONG_EDGE dummy
setLongEdgeSourceAndTarget(dummy, dummyInput, dummyOutput, eastwardPort);
// Move head labels from the old edge over to the new one
ListIterator<LLabel> labelIterator = edge.getLabels().listIterator();
while (labelIterator.hasNext()) {
LLabel label = labelIterator.next();
EdgeLabelPlacement labelPlacement = label.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT);
if (labelPlacement == EdgeLabelPlacement.HEAD) {
// Remember which edge the label originally belonged to, unless it already knows
if (!label.hasProperty(InternalProperties.END_LABEL_EDGE)) {
label.setProperty(InternalProperties.END_LABEL_EDGE, edge);
}
labelIterator.remove();
dummyEdge.getLabels().add(label);
}
}
}
use of org.eclipse.elk.alg.layered.graph.LNode in project elk by eclipse.
the class InvertedPortProcessor method setLongEdgeSourceAndTarget.
/**
* Properly sets the
* {@link org.eclipse.elk.alg.layered.options.LayeredOptions#LONG_EDGE_SOURCE} and
* {@link org.eclipse.elk.alg.layered.options.LayeredOptions#LONG_EDGE_TARGET} properties for
* the given long edge dummy. This is required for the
* {@link org.eclipse.elk.alg.layered.intermediate.HyperedgeDummyMerger} to work correctly.
*
* @param longEdgeDummy
* the long edge dummy whose properties to set.
* @param dummyInputPort
* the dummy node's input port.
* @param dummyOutputPort
* the dummy node's output port.
* @param oddPort
* the odd port that prompted the dummy to be created.
*/
private void setLongEdgeSourceAndTarget(final LNode longEdgeDummy, final LPort dummyInputPort, final LPort dummyOutputPort, final LPort oddPort) {
// There's exactly one edge connected to the input and output port
LPort sourcePort = dummyInputPort.getIncomingEdges().get(0).getSource();
LNode sourceNode = sourcePort.getNode();
NodeType sourceNodeType = sourceNode.getType();
LPort targetPort = dummyOutputPort.getOutgoingEdges().get(0).getTarget();
LNode targetNode = targetPort.getNode();
NodeType targetNodeType = targetNode.getType();
// Set the LONG_EDGE_SOURCE property
if (sourceNodeType == NodeType.LONG_EDGE) {
// The source is a LONG_EDGE node; use its LONG_EDGE_SOURCE
longEdgeDummy.setProperty(InternalProperties.LONG_EDGE_SOURCE, sourceNode.getProperty(InternalProperties.LONG_EDGE_SOURCE));
} else {
// The target is the original node; use it
longEdgeDummy.setProperty(InternalProperties.LONG_EDGE_SOURCE, sourcePort);
}
// Set the LONG_EDGE_TARGET property
if (targetNodeType == NodeType.LONG_EDGE) {
// The target is a LONG_EDGE node; use its LONG_EDGE_TARGET
longEdgeDummy.setProperty(InternalProperties.LONG_EDGE_TARGET, targetNode.getProperty(InternalProperties.LONG_EDGE_TARGET));
} else {
// The target is the original node; use it
longEdgeDummy.setProperty(InternalProperties.LONG_EDGE_TARGET, targetPort);
}
}
use of org.eclipse.elk.alg.layered.graph.LNode in project elk by eclipse.
the class InvertedPortProcessor method process.
@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Inverted port preprocessing", 1);
// Retrieve the layers in the graph
List<Layer> layers = layeredGraph.getLayers();
// Iterate through the layers and for each layer create a list of dummy nodes
// that were created, but not yet assigned to the layer (to avoid concurrent
// modification exceptions)
ListIterator<Layer> layerIterator = layers.listIterator();
Layer currentLayer = null;
List<LNode> unassignedNodes = Lists.newArrayList();
while (layerIterator.hasNext()) {
// Update previous and current layers
Layer previousLayer = currentLayer;
currentLayer = layerIterator.next();
// If the previous layer had unassigned nodes, assign them now and clear the list
for (LNode node : unassignedNodes) {
node.setLayer(previousLayer);
}
unassignedNodes.clear();
// Iterate through the layer's nodes
for (LNode node : currentLayer) {
// Skip dummy nodes
if (node.getType() != NodeType.NORMAL) {
continue;
}
// port side problem won't appear)
if (!node.getProperty(LayeredOptions.PORT_CONSTRAINTS).isSideFixed()) {
continue;
}
// Look for input ports on the right side
for (LPort port : node.getPorts(PortType.INPUT, PortSide.EAST)) {
// For every edge going into this port, insert dummy nodes (do this using
// a copy of the current list of edges, since the edges are modified when
// dummy nodes are created)
List<LEdge> edges = port.getIncomingEdges();
LEdge[] edgeArray = LGraphUtil.toEdgeArray(edges);
for (LEdge edge : edgeArray) {
createEastPortSideDummies(layeredGraph, port, edge, unassignedNodes);
}
}
// Look for ports on the left side connected to edges going to higher layers
for (LPort port : node.getPorts(PortType.OUTPUT, PortSide.WEST)) {
// For every edge going out of this port, insert dummy nodes (do this using
// a copy of the current list of edges, since the edges are modified when
// dummy nodes are created)
List<LEdge> edges = port.getOutgoingEdges();
LEdge[] edgeArray = LGraphUtil.toEdgeArray(edges);
for (LEdge edge : edgeArray) {
createWestPortSideDummies(layeredGraph, port, edge, unassignedNodes);
}
}
}
}
// There may be unassigned nodes left
for (LNode node : unassignedNodes) {
node.setLayer(currentLayer);
}
monitor.done();
}
use of org.eclipse.elk.alg.layered.graph.LNode in project elk by eclipse.
the class LabelDummyInserter method createLabelDummy.
/**
* Creates a label dummy for the given edge.
*
* @param layeredGraph
* graph the dummy will later be placed in.
* @param edge
* the edge the label dummy is created for.
* @param thickness
* the edge's thickness.
* @param representedLabels
* currently empty list of labels represented by the new label dummy. This is set on the edge as a
* property and will later be filled with the represented labels by the calling method.
*/
private LNode createLabelDummy(final LGraph layeredGraph, final LEdge edge, final double thickness, final List<LLabel> representedLabels) {
LNode dummyNode = new LNode(layeredGraph);
dummyNode.setType(NodeType.LABEL);
dummyNode.setProperty(InternalProperties.ORIGIN, edge);
dummyNode.setProperty(InternalProperties.REPRESENTED_LABELS, representedLabels);
dummyNode.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS);
dummyNode.setProperty(InternalProperties.LONG_EDGE_SOURCE, edge.getSource());
dummyNode.setProperty(InternalProperties.LONG_EDGE_TARGET, edge.getTarget());
// Actually split the edge
LongEdgeSplitter.splitEdge(edge, dummyNode);
// Place ports at the edge's center
double portPos = Math.floor(thickness / 2);
for (LPort dummyPort : dummyNode.getPorts()) {
dummyPort.getPosition().y = portPos;
}
return dummyNode;
}
Aggregations