use of org.eclipse.elk.alg.layered.graph.LLabel 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.LLabel in project elk by eclipse.
the class LabelDummySwitcher method assignLayer.
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Swapping Utilities
/**
* Assigns the given label dummy to the layer with the given index. Updates the layer size if the label enlarges
* the layer.
*/
private void assignLayer(final LabelDummyInfo labelDummyInfo, final int targetLayerIndex) {
assert targetLayerIndex < labelDummyInfo.labelDummy.getGraph().getLayers().size();
// If the label dummy is not in the target layer yet, swap it with the long edge dummy that is
if (targetLayerIndex != labelDummyInfo.leftmostLayerId + labelDummyInfo.leftLongEdgeDummies.size()) {
swapNodes(labelDummyInfo.labelDummy, labelDummyInfo.ithDummyNode(targetLayerIndex - labelDummyInfo.leftmostLayerId));
}
// Update the size information of the label dummy's new layer
int newLayerId = labelDummyInfo.labelDummy.getLayer().id;
layerWidths[newLayerId] = Math.max(layerWidths[newLayerId], labelDummyInfo.labelDummy.getSize().x);
for (LLabel label : labelDummyInfo.labelDummy.getProperty(InternalProperties.REPRESENTED_LABELS)) {
label.setProperty(INCLUDE_LABEL, true);
}
}
use of org.eclipse.elk.alg.layered.graph.LLabel in project elk by eclipse.
the class LabelManagementProcessor method doManageLabels.
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Actual Label Management
/**
* Manage all the labels according to the labelManager and change the labels size.
*
* @param labelManager
* the label manager used to manage labels.
* @param labels
* the labels to be passed to the label manager.
* @param targetWidth
* the target width.
* @param labelLabelSpacing
* spacing between two adjacent labels
* @param verticalLayout
* {@code true} if the graph is laid out downwards or upwards. In these cases, the new label dimensions
* returned by the label manager need to be turned 90 degrees.
* @return size required to place the labels. Does not include the edge-label space yet.
*/
public static KVector doManageLabels(final ILabelManager labelManager, final Iterable<LLabel> labels, final double targetWidth, final double labelLabelSpacing, final boolean verticalLayout) {
KVector requiredLabelSpace = new KVector();
// Manage all of them labels, if there are any
if (labels.iterator().hasNext()) {
for (LLabel label : labels) {
KVector labelSize = label.getSize();
// If the label has an origin, call the label size modifier
Object origin = label.getProperty(InternalProperties.ORIGIN);
if (origin != null) {
KVector newSize = labelManager.manageLabelSize(origin, targetWidth);
if (newSize != null) {
if (verticalLayout) {
// Our labels are turned 90 degrees
labelSize.x = newSize.y;
labelSize.y = newSize.x;
} else {
labelSize.x = newSize.x;
labelSize.y = newSize.y;
}
}
}
// Update required label space
if (verticalLayout) {
requiredLabelSpace.x += labelLabelSpacing + label.getSize().x;
requiredLabelSpace.y = Math.max(requiredLabelSpace.y, labelSize.y);
} else {
requiredLabelSpace.x = Math.max(requiredLabelSpace.x, labelSize.x);
requiredLabelSpace.y += labelLabelSpacing + label.getSize().y;
}
}
// There is one label-label spacing too much
if (verticalLayout) {
requiredLabelSpace.x -= labelLabelSpacing;
} else {
requiredLabelSpace.y -= labelLabelSpacing;
}
}
return requiredLabelSpace;
}
use of org.eclipse.elk.alg.layered.graph.LLabel in project elk by eclipse.
the class LabelSideSelector method smartForRegularNode.
/**
* Assigns label sides to all end labels incident to this node. The assigned label sides depend on how many ports
* there are on any given side.
*/
private void smartForRegularNode(final LNode node, final LabelSide defaultSide) {
// Iterate over the node's list of ports on each side. Remember the ones that have edges connected to them
// and make the label side decision based on how many such ports there are
Queue<List<LLabel>> endLabelQueue = new ArrayDeque<>(node.getPorts().size());
PortSide currentPortSide = null;
// This is where we assume that the list of ports is properly sorted
for (LPort port : node.getPorts()) {
if (port.getSide() != currentPortSide) {
if (!endLabelQueue.isEmpty()) {
smartForRegularNodePortEndLabels(endLabelQueue, currentPortSide, defaultSide);
}
endLabelQueue.clear();
currentPortSide = port.getSide();
}
// Possibly add the port's end labels to our queue, if it has any
List<LLabel> portEndLabels = EndLabelPreprocessor.gatherLabels(port);
if (portEndLabels != null) {
endLabelQueue.add(portEndLabels);
}
}
// Clear remaining ports
if (!endLabelQueue.isEmpty()) {
smartForRegularNodePortEndLabels(endLabelQueue, currentPortSide, defaultSide);
}
}
use of org.eclipse.elk.alg.layered.graph.LLabel in project elk by eclipse.
the class CompoundGraphPreprocessor method transformHierarchyEdges.
/**
* Recursively transform cross-hierarchy edges into sequences of dummy ports and dummy edges.
*
* @param graph
* the layered graph to process
* @param parentNode
* the node that represents the graph in the upper hierarchy level, or {@code null}
* if it already is on top-level
* @return the external ports created to split edges that cross the boundary of the parent node
*/
private List<ExternalPort> transformHierarchyEdges(final LGraph graph, final LNode parentNode) {
// process all children and recurse down to gather their external ports
List<ExternalPort> containedExternalPorts = Lists.newArrayList();
for (LNode node : graph.getLayerlessNodes()) {
LGraph nestedGraph = node.getNestedGraph();
if (nestedGraph != null) {
// recursively process the child graph
List<ExternalPort> childPorts = transformHierarchyEdges(nestedGraph, node);
containedExternalPorts.addAll(childPorts);
// process inside self loops
processInsideSelfLoops(nestedGraph, node);
// will already have been created, but perhaps not all)
if (nestedGraph.getProperty(InternalProperties.GRAPH_PROPERTIES).contains(GraphProperties.EXTERNAL_PORTS)) {
// We need the port constraints to position external ports (Issues KIPRA-1528, ELK-48)
PortConstraints portConstraints = node.getProperty(LayeredOptions.PORT_CONSTRAINTS);
boolean insidePortLabels = node.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT).contains(PortLabelPlacement.INSIDE);
for (LPort port : node.getPorts()) {
// Make sure that every port has a dummy node created for it
LNode dummyNode = dummyNodeMap.get(port);
if (dummyNode == null) {
dummyNode = LGraphUtil.createExternalPortDummy(port, portConstraints, port.getSide(), -port.getNetFlow(), null, new KVector(), port.getSize(), nestedGraph.getProperty(LayeredOptions.DIRECTION), nestedGraph);
dummyNode.setProperty(InternalProperties.ORIGIN, port);
dummyNodeMap.put(port, dummyNode);
nestedGraph.getLayerlessNodes().add(dummyNode);
}
// We need to reserve space for external port labels by adding those labels to our dummy nodes
LPort dummyNodePort = dummyNode.getPorts().get(0);
for (LLabel extPortLabel : port.getLabels()) {
LLabel dummyPortLabel = new LLabel();
dummyPortLabel.getSize().x = extPortLabel.getSize().x;
dummyPortLabel.getSize().y = extPortLabel.getSize().y;
dummyNodePort.getLabels().add(dummyPortLabel);
// But if the port labels are fixed, we should consider the part that is inside the node.
if (!insidePortLabels) {
PortSide side = port.getSide();
double insidePart = 0;
if (PortLabelPlacement.isFixed(node.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT))) {
// We use 0 as port border offset here, as we only want the label part that is
// inside the node "after" the port.
insidePart = ElkUtil.computeInsidePart(extPortLabel.getPosition(), extPortLabel.getSize(), port.getSize(), 0, side);
}
if (portConstraints == PortConstraints.FREE || PortSide.SIDES_EAST_WEST.contains(side)) {
dummyPortLabel.getSize().x = insidePart;
} else {
dummyPortLabel.getSize().y = insidePart;
}
}
}
}
}
}
}
// this will be the list of external ports we will export
List<ExternalPort> exportedExternalPorts = Lists.newArrayList();
// process the cross-hierarchy edges connected to the inside of the child nodes
processInnerHierarchicalEdgeSegments(graph, parentNode, containedExternalPorts, exportedExternalPorts);
// process the cross-hierarchy edges connected to the outside of the parent node
if (parentNode != null) {
processOuterHierarchicalEdgeSegments(graph, parentNode, exportedExternalPorts);
}
return exportedExternalPorts;
}
Aggregations