Search in sources :

Example 31 with LLabel

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));
            }
        }
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) KVector(org.eclipse.elk.core.math.KVector)

Example 32 with LLabel

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);
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel)

Example 33 with LLabel

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;
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) KVector(org.eclipse.elk.core.math.KVector)

Example 34 with LLabel

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);
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LPort(org.eclipse.elk.alg.layered.graph.LPort) List(java.util.List) PortSide(org.eclipse.elk.core.options.PortSide) ArrayDeque(java.util.ArrayDeque)

Example 35 with LLabel

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;
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) KVector(org.eclipse.elk.core.math.KVector) PortSide(org.eclipse.elk.core.options.PortSide) PortConstraints(org.eclipse.elk.core.options.PortConstraints)

Aggregations

LLabel (org.eclipse.elk.alg.layered.graph.LLabel)38 LPort (org.eclipse.elk.alg.layered.graph.LPort)20 LNode (org.eclipse.elk.alg.layered.graph.LNode)19 KVector (org.eclipse.elk.core.math.KVector)19 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)14 KVectorChain (org.eclipse.elk.core.math.KVectorChain)8 PortSide (org.eclipse.elk.core.options.PortSide)5 List (java.util.List)4 ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)4 ElkLabel (org.eclipse.elk.graph.ElkLabel)4 LabelCell (org.eclipse.elk.alg.common.nodespacing.cellsystem.LabelCell)3 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)3 Layer (org.eclipse.elk.alg.layered.graph.Layer)3 EdgeLabelPlacement (org.eclipse.elk.core.options.EdgeLabelPlacement)3 Lists (com.google.common.collect.Lists)2 LMargin (org.eclipse.elk.alg.layered.graph.LMargin)2 InternalProperties (org.eclipse.elk.alg.layered.options.InternalProperties)2 LayeredOptions (org.eclipse.elk.alg.layered.options.LayeredOptions)2 Direction (org.eclipse.elk.core.options.Direction)2 PortConstraints (org.eclipse.elk.core.options.PortConstraints)2