use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class InvertedPortProcessor method createWestPortSideDummies.
/**
* Creates the necessary dummy nodes for an output port on the west side of a node, provided
* that the edge connects two different nodes.
*
* @param layeredGraph
* the layered graph
* @param westwardPort
* 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 createWestPortSideDummies(final LGraph layeredGraph, final LPort westwardPort, final LEdge edge, final List<LNode> layerNodeList) {
assert edge.getSource() == westwardPort;
// Ignore self loops
if (edge.getTarget().getNode() == westwardPort.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
LPort originalTarget = edge.getTarget();
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(originalTarget);
// Move any head labels over to the new dummy edge
ListIterator<LLabel> labelIterator = edge.getLabels().listIterator();
while (labelIterator.hasNext()) {
LLabel label = labelIterator.next();
if (label.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT) == EdgeLabelPlacement.HEAD) {
// Remember which edge the label belonged to originally
assert !label.hasProperty(InternalProperties.END_LABEL_EDGE);
label.setProperty(InternalProperties.END_LABEL_EDGE, edge);
labelIterator.remove();
dummyEdge.getLabels().add(label);
}
}
// Set LONG_EDGE_SOURCE and LONG_EDGE_TARGET properties on the LONG_EDGE dummy
setLongEdgeSourceAndTarget(dummy, dummyInput, dummyOutput, westwardPort);
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class LabelDummyInserter method process.
@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Label dummy insertions", 1);
// We cannot add the nodes to the graph while we're iterating over it, so remember the dummy nodes we create
List<LNode> newDummyNodes = Lists.newArrayList();
double edgeLabelSpacing = layeredGraph.getProperty(LayeredOptions.SPACING_EDGE_LABEL);
double labelLabelSpacing = layeredGraph.getProperty(LayeredOptions.SPACING_LABEL_LABEL);
Direction layoutDirection = layeredGraph.getProperty(LayeredOptions.DIRECTION);
for (LNode node : layeredGraph.getLayerlessNodes()) {
for (LEdge edge : node.getOutgoingEdges()) {
if (edgeNeedsToBeProcessed(edge)) {
double thickness = retrieveThickness(edge);
// Create dummy node and remember represented labels (to be filled below)
List<LLabel> representedLabels = Lists.newArrayListWithCapacity(edge.getLabels().size());
LNode dummyNode = createLabelDummy(layeredGraph, edge, thickness, representedLabels);
newDummyNodes.add(dummyNode);
// Determine the size of the dummy node and move labels over to it
KVector dummySize = dummyNode.getSize();
ListIterator<LLabel> iterator = edge.getLabels().listIterator();
while (iterator.hasNext()) {
LLabel label = iterator.next();
if (label.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT) == EdgeLabelPlacement.CENTER) {
// The way we stack labels depends on the layout direction
if (layoutDirection.isVertical()) {
dummySize.x += label.getSize().x + labelLabelSpacing;
dummySize.y = Math.max(dummySize.y, label.getSize().y);
} else {
dummySize.x = Math.max(dummySize.x, label.getSize().x);
dummySize.y += label.getSize().y + labelLabelSpacing;
}
// Move the label over to the dummy node's REPRESENTED_LABELS property
representedLabels.add(label);
iterator.remove();
}
}
// edge-label spacing yet
if (layoutDirection.isVertical()) {
dummySize.x -= labelLabelSpacing;
dummySize.y += edgeLabelSpacing + thickness;
} else {
dummySize.y += edgeLabelSpacing - labelLabelSpacing + thickness;
}
}
}
}
// Add created dummies to graph
layeredGraph.getLayerlessNodes().addAll(newDummyNodes);
monitor.done();
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class LabelDummyRemover method process.
@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Label dummy removal", 1);
double edgeLabelSpacing = layeredGraph.getProperty(LayeredOptions.SPACING_EDGE_LABEL);
double labelLabelSpacing = layeredGraph.getProperty(LayeredOptions.SPACING_LABEL_LABEL);
Direction layoutDirection = layeredGraph.getProperty(LayeredOptions.DIRECTION);
for (Layer layer : layeredGraph.getLayers()) {
// An iterator is necessary for traversing nodes, since dummy nodes might be removed
ListIterator<LNode> nodeIterator = layer.getNodes().listIterator();
while (nodeIterator.hasNext()) {
LNode node = nodeIterator.next();
if (node.getType() == NodeType.LABEL) {
// First, place labels on position of dummy node
LEdge originEdge = (LEdge) node.getProperty(InternalProperties.ORIGIN);
double thickness = originEdge.getProperty(LayeredOptions.EDGE_THICKNESS).doubleValue();
boolean labelsBelowEdge = node.getProperty(InternalProperties.LABEL_SIDE) == LabelSide.BELOW;
KVector currLabelPos = new KVector(node.getPosition());
// position down a bit to respect the label spacing
if (labelsBelowEdge) {
currLabelPos.y += thickness + edgeLabelSpacing;
}
// Calculate the space available for the placement of labels
KVector labelSpace = new KVector(node.getSize().x, node.getSize().y - thickness - edgeLabelSpacing);
// Place labels
List<LLabel> representedLabels = node.getProperty(InternalProperties.REPRESENTED_LABELS);
if (layoutDirection.isVertical()) {
placeLabelsForVerticalLayout(representedLabels, currLabelPos, labelLabelSpacing, labelSpace, labelsBelowEdge, layoutDirection);
} else {
placeLabelsForHorizontalLayout(representedLabels, currLabelPos, labelLabelSpacing, labelSpace);
}
// Add represented labels back to the original edge
originEdge.getLabels().addAll(representedLabels);
// Whether we need to add unnecessary bend points around the label dummy depends on the edge
// router. For orthogonal edge routing, they are not necessary. For splines, they may even be
// harmful. For polylines, they are necessary to keep the routes edges take close to their labels
LongEdgeJoiner.joinAt(node, layeredGraph.getProperty(LayeredOptions.EDGE_ROUTING) == EdgeRouting.POLYLINE);
// Remove the node
nodeIterator.remove();
}
}
}
monitor.done();
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class LongEdgeJoiner method joinAt.
/**
* Joins the edges connected to the given dummy node. The dummy node is then ready to be removed
* from the graph.
*
* @param longEdgeDummy
* the dummy node whose incident edges to join.
* @param addUnnecessaryBendpoints
* {@code true} if a bend point should be added to the edges at the position of the
* dummy node.
*/
public static void joinAt(final LNode longEdgeDummy, final boolean addUnnecessaryBendpoints) {
// Get the input and output port (of which we assume to have only one, on the western side and
// on the eastern side, respectively); the incoming edges are retained, and the outgoing edges
// are discarded
List<LEdge> inputPortEdges = longEdgeDummy.getPorts(PortSide.WEST).iterator().next().getIncomingEdges();
List<LEdge> outputPortEdges = longEdgeDummy.getPorts(PortSide.EAST).iterator().next().getOutgoingEdges();
int edgeCount = inputPortEdges.size();
// If we are to add unnecessary bend points, we need to know where. We take the position of the
// first port we find. (It doesn't really matter which port we're using, so we opt to keep it
// surprisingly simple.)
KVector unnecessaryBendpoint = longEdgeDummy.getPorts().get(0).getAbsoluteAnchor();
// HyperedgeDummyMerger
while (edgeCount-- > 0) {
// Get the two edges
LEdge survivingEdge = inputPortEdges.get(0);
LEdge droppedEdge = outputPortEdges.get(0);
// The surviving edge's target needs to be set to the old target of the dropped edge.
// However, this doesn't replace the dropped edge with the surviving edge in the list of
// incoming edges of the (new) target port, but instead appends the surviving edge. That in
// turn messes with the implicit assumption that edges with the same index on input and
// output ports of long edge dummies belong to each other. Thus, we need to ensure that the
// surviving edge is at the correct index in the list of incoming edges. Hence the
// complicated code below. (KIPRA-1670)
List<LEdge> targetIncomingEdges = droppedEdge.getTarget().getIncomingEdges();
int droppedEdgeListIndex = targetIncomingEdges.indexOf(droppedEdge);
survivingEdge.setTargetAndInsertAtIndex(droppedEdge.getTarget(), droppedEdgeListIndex);
// Remove the dropped edge from the graph
droppedEdge.setSource(null);
droppedEdge.setTarget(null);
// Join their bend points and add possibly an unnecessary one
KVectorChain survivingBendPoints = survivingEdge.getBendPoints();
if (addUnnecessaryBendpoints) {
survivingBendPoints.add(new KVector(unnecessaryBendpoint));
}
for (KVector bendPoint : droppedEdge.getBendPoints()) {
survivingBendPoints.add(new KVector(bendPoint));
}
// Join their labels
List<LLabel> survivingLabels = survivingEdge.getLabels();
for (LLabel label : droppedEdge.getLabels()) {
survivingLabels.add(label);
}
// Join their junction points
KVectorChain survivingJunctionPoints = survivingEdge.getProperty(LayeredOptions.JUNCTION_POINTS);
KVectorChain droppedJunctionsPoints = droppedEdge.getProperty(LayeredOptions.JUNCTION_POINTS);
if (droppedJunctionsPoints != null) {
if (survivingJunctionPoints == null) {
survivingJunctionPoints = new KVectorChain();
survivingEdge.setProperty(LayeredOptions.JUNCTION_POINTS, survivingJunctionPoints);
}
for (KVector jp : droppedJunctionsPoints) {
survivingJunctionPoints.add(new KVector(jp));
}
}
}
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class LongEdgeSplitter method process.
@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Edge splitting", 1);
if (layeredGraph.getLayers().size() <= 2) {
monitor.done();
return;
}
// Iterate through the layers
ListIterator<Layer> layerIter = layeredGraph.getLayers().listIterator();
Layer nextLayer = layerIter.next();
while (layerIter.hasNext()) {
Layer layer = nextLayer;
nextLayer = layerIter.next();
// Iterate through the nodes
for (LNode node : layer) {
// Iterate through the outgoing edges
for (LPort port : node.getPorts()) {
// Iterate through the edges
for (LEdge edge : port.getOutgoingEdges()) {
LPort targetPort = edge.getTarget();
Layer targetLayer = targetPort.getNode().getLayer();
// If the edge doesn't go to the current or next layer, split it
if (targetLayer != layer && targetLayer != nextLayer) {
// If there is no next layer, something is wrong
assert layerIter.hasNext();
// Split the edge
splitEdge(edge, createDummyNode(layeredGraph, nextLayer, edge));
}
}
}
}
}
monitor.done();
}
Aggregations