use of org.eclipse.elk.alg.layered.graph.Layer in project elk by eclipse.
the class HierarchicalPortOrthogonalEdgeRouter method removeTemporaryNorthSouthDummies.
// /////////////////////////////////////////////////////////////////////////////
// STEP 4: REMOVE TEMPORARY DUMMIES
/**
* Removes the temporary hierarchical port dummies, reconnecting their incoming and outgoing
* edges to the original dummies and setting the appropriate bend points.
*
* @param layeredGraph the layered graph.
*/
private void removeTemporaryNorthSouthDummies(final LGraph layeredGraph) {
List<LNode> nodesToRemove = Lists.newArrayList();
// Iterate through all layers
for (Layer layer : layeredGraph) {
for (LNode node : layer) {
if (node.getType() != NodeType.EXTERNAL_PORT) {
// We're only looking for hierarchical port dummies
continue;
}
if (!node.hasProperty(InternalProperties.EXT_PORT_REPLACED_DUMMY)) {
// We're only looking for temporary north / south dummies
continue;
}
// There must be a port where all edges come in, another port where edges go out, and
// a port with an edge connecting node and origin (that one was added previously by
// this processor)
LPort nodeInPort = null;
LPort nodeOutPort = null;
LPort nodeOriginPort = null;
for (LPort port : node.getPorts()) {
switch(port.getSide()) {
case WEST:
nodeInPort = port;
break;
case EAST:
nodeOutPort = port;
break;
default:
nodeOriginPort = port;
}
}
// Find the edge connecting this dummy to the original external port dummy that we
// restored just a while ago
LEdge nodeToOriginEdge = nodeOriginPort.getOutgoingEdges().get(0);
// Compute bend points for incoming edges
KVectorChain incomingEdgeBendPoints = new KVectorChain(nodeToOriginEdge.getBendPoints());
KVector firstBendPoint = new KVector(nodeOriginPort.getPosition());
firstBendPoint.add(node.getPosition());
incomingEdgeBendPoints.add(0, firstBendPoint);
// Compute bend points for outgoing edges
KVectorChain outgoingEdgeBendPoints = KVectorChain.reverse(nodeToOriginEdge.getBendPoints());
KVector lastBendPoint = new KVector(nodeOriginPort.getPosition());
lastBendPoint.add(node.getPosition());
outgoingEdgeBendPoints.add(lastBendPoint);
// Retrieve the original hierarchical port dummy
LNode replacedDummy = (LNode) node.getProperty(InternalProperties.EXT_PORT_REPLACED_DUMMY);
LPort replacedDummyPort = replacedDummy.getPorts().get(0);
// Reroute all the input port's edges
LEdge[] edges = nodeInPort.getIncomingEdges().toArray(new LEdge[0]);
for (LEdge edge : edges) {
edge.setTarget(replacedDummyPort);
edge.getBendPoints().addAllAsCopies(edge.getBendPoints().size(), incomingEdgeBendPoints);
}
// Reroute all the output port's edges
edges = LGraphUtil.toEdgeArray(nodeOutPort.getOutgoingEdges());
for (LEdge edge : edges) {
edge.setSource(replacedDummyPort);
edge.getBendPoints().addAllAsCopies(0, outgoingEdgeBendPoints);
}
// Remove connection between node and original hierarchical port dummy
nodeToOriginEdge.setSource(null);
nodeToOriginEdge.setTarget(null);
// Remember the temporary node for removal
nodesToRemove.add(node);
}
}
// Remove nodes
for (LNode node : nodesToRemove) {
node.setLayer(null);
}
}
use of org.eclipse.elk.alg.layered.graph.Layer 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.Layer 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.Layer in project elk by eclipse.
the class LabelAndNodeSizeProcessor method process.
@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Node and Port Label Placement and Node Sizing", 1);
NodeDimensionCalculation.calculateLabelAndNodeSizes(LGraphAdapters.adapt(layeredGraph, true, true, node -> node.getType() == NodeType.NORMAL));
// which is the reason why we haven't handed them to the label and node size processing code
if (layeredGraph.getProperty(InternalProperties.GRAPH_PROPERTIES).contains(GraphProperties.EXTERNAL_PORTS)) {
Set<PortLabelPlacement> portLabelPlacement = layeredGraph.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT);
boolean placeNextToPort = portLabelPlacement.contains(PortLabelPlacement.NEXT_TO_PORT_IF_POSSIBLE);
boolean treatAsGroup = layeredGraph.getProperty(LayeredOptions.PORT_LABELS_TREAT_AS_GROUP);
for (Layer layer : layeredGraph.getLayers()) {
layer.getNodes().stream().filter(node -> node.getType() == NodeType.EXTERNAL_PORT).forEach(dummy -> placeExternalPortDummyLabels(dummy, portLabelPlacement, placeNextToPort, treatAsGroup));
}
}
monitor.done();
}
use of org.eclipse.elk.alg.layered.graph.Layer in project elk by eclipse.
the class LabelDummySwitcher method swapNodes.
/**
* Swaps the two given label dummy with the given long edge dummy. The dummies are assumed to be part of the same
* long edge. The label dummy's new layer's width in the {@link #layerWidths} array is enlarged if the label dummy
* is wider than the layer currently is.
*/
private void swapNodes(final LNode labelDummy, final LNode longEdgeDummy) {
// Find the layers and the positions inside the layers of the dummy nodes. We need the positions later since
// we run after crossing minimization and have to keep the order of nodes the same. An alternative for this
// method would be not to change the layers and connections of the two nodes but to switch all of their
// properties instead, but we reckon that might actually be more work
Layer layer1 = labelDummy.getLayer();
Layer layer2 = longEdgeDummy.getLayer();
int dummy1LayerPosition = layer1.getNodes().indexOf(labelDummy);
int dummy2LayerPosition = layer2.getNodes().indexOf(longEdgeDummy);
// Detect incoming and outgoing ports of the nodes (this of course assumes that there's just one of each kind,
// which should be true for long edge and label dummy nodes)
LPort inputPort1 = labelDummy.getPorts(PortType.INPUT).iterator().next();
LPort outputPort1 = labelDummy.getPorts(PortType.OUTPUT).iterator().next();
LPort inputPort2 = longEdgeDummy.getPorts(PortType.INPUT).iterator().next();
LPort outputPort2 = longEdgeDummy.getPorts(PortType.OUTPUT).iterator().next();
// Store incoming and outgoing edges
LEdge[] incomingEdges1 = LGraphUtil.toEdgeArray(inputPort1.getIncomingEdges());
LEdge[] outgoingEdges1 = LGraphUtil.toEdgeArray(outputPort1.getOutgoingEdges());
LEdge[] incomingEdges2 = LGraphUtil.toEdgeArray(inputPort2.getIncomingEdges());
LEdge[] outgoingEdges2 = LGraphUtil.toEdgeArray(outputPort2.getOutgoingEdges());
// Put first dummy into second dummy's layer and reroute second dummy's edges to first dummy
labelDummy.setLayer(dummy2LayerPosition, layer2);
for (LEdge edge : incomingEdges2) {
edge.setTarget(inputPort1);
}
for (LEdge edge : outgoingEdges2) {
edge.setSource(outputPort1);
}
// Put second dummy into first dummy's layer and reroute first dummy's edges to second dummy
longEdgeDummy.setLayer(dummy1LayerPosition, layer1);
for (LEdge edge : incomingEdges1) {
edge.setTarget(inputPort2);
}
for (LEdge edge : outgoingEdges1) {
edge.setSource(outputPort2);
}
}
Aggregations