Search in sources :

Example 26 with LLabel

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

Example 27 with LLabel

use of org.eclipse.elk.alg.layered.graph.LLabel in project elk by eclipse.

the class LabelAndNodeSizeProcessor method placeExternalPortDummyLabels.

/**
 * Places the labels of the given external port dummy such that it results in correct node margins later on that
 * will reserve enough space for the labels to be placed once label and node placement is called on the graph.
 */
private void placeExternalPortDummyLabels(final LNode dummy, final Set<PortLabelPlacement> graphPortLabelPlacement, final boolean placeNextToPortIfPossible, final boolean treatAsGroup) {
    double labelPortSpacing = dummy.getProperty(LayeredOptions.SPACING_LABEL_PORT);
    double labelLabelSpacing = dummy.getProperty(LayeredOptions.SPACING_LABEL_LABEL);
    KVector dummySize = dummy.getSize();
    // External port dummies have exactly one port (see ElkGraphImporter)
    LPort dummyPort = dummy.getPorts().get(0);
    KVector dummyPortPos = dummyPort.getPosition();
    ElkRectangle portLabelBox = computePortLabelBox(dummyPort, labelLabelSpacing);
    if (portLabelBox == null) {
        return;
    }
    // TODO We could handle FIXED here as well
    if (graphPortLabelPlacement.contains(PortLabelPlacement.INSIDE)) {
        // (port label placement has to support this case first, though)
        switch(dummy.getProperty(InternalProperties.EXT_PORT_SIDE)) {
            case NORTH:
                portLabelBox.x = (dummySize.x - portLabelBox.width) / 2 - dummyPortPos.x;
                portLabelBox.y = labelPortSpacing;
                break;
            case SOUTH:
                portLabelBox.x = (dummySize.x - portLabelBox.width) / 2 - dummyPortPos.x;
                portLabelBox.y = -labelPortSpacing - portLabelBox.height;
                break;
            case EAST:
                if (labelNextToPort(dummyPort, true, placeNextToPortIfPossible)) {
                    double labelHeight = treatAsGroup ? portLabelBox.height : dummyPort.getLabels().get(0).getSize().y;
                    portLabelBox.y = (dummySize.y - labelHeight) / 2 - dummyPortPos.y;
                } else {
                    portLabelBox.y = dummySize.y + labelPortSpacing - dummyPortPos.y;
                }
                portLabelBox.x = -labelPortSpacing - portLabelBox.width;
                break;
            case WEST:
                if (labelNextToPort(dummyPort, true, placeNextToPortIfPossible)) {
                    double labelHeight = treatAsGroup ? portLabelBox.height : dummyPort.getLabels().get(0).getSize().y;
                    portLabelBox.y = (dummySize.y - labelHeight) / 2 - dummyPortPos.y;
                } else {
                    portLabelBox.y = dummySize.y + labelPortSpacing - dummyPortPos.y;
                }
                portLabelBox.x = labelPortSpacing;
                break;
        }
    } else if (graphPortLabelPlacement.contains(PortLabelPlacement.OUTSIDE)) {
        switch(dummy.getProperty(InternalProperties.EXT_PORT_SIDE)) {
            case NORTH:
            case SOUTH:
                portLabelBox.x = dummyPortPos.x + labelPortSpacing;
                break;
            case EAST:
            case WEST:
                if (labelNextToPort(dummyPort, false, placeNextToPortIfPossible)) {
                    double labelHeight = treatAsGroup ? portLabelBox.height : dummyPort.getLabels().get(0).getSize().y;
                    portLabelBox.y = (dummySize.y - labelHeight) / 2 - dummyPortPos.y;
                } else {
                    portLabelBox.y = dummyPortPos.y + labelPortSpacing;
                }
                break;
        }
    }
    // Place the labels
    double currentY = portLabelBox.y;
    for (LLabel label : dummyPort.getLabels()) {
        KVector labelPos = label.getPosition();
        labelPos.x = portLabelBox.x;
        labelPos.y = currentY;
        currentY += label.getSize().y + labelLabelSpacing;
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LPort(org.eclipse.elk.alg.layered.graph.LPort) KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle)

Example 28 with LLabel

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

Example 29 with LLabel

use of org.eclipse.elk.alg.layered.graph.LLabel in project elk by eclipse.

the class LabelDummyRemover method placeLabelsForVerticalLayout.

private void placeLabelsForVerticalLayout(final List<LLabel> labels, final KVector labelPos, final double labelSpacing, final KVector labelSpace, final boolean leftAligned, final Direction layoutDirection) {
    // We may have to override the alignment if all labels here are inline labels
    boolean inline = labels.stream().allMatch(label -> label.getProperty(LayeredOptions.EDGE_LABELS_INLINE));
    // Due to the way layout directions work, we need to pay attention to the order in which we place labels. While
    // we can simply place them as they come for the DOWN direction, doing the same for the UP direction will
    // reverse the label order in the final result. Thus, in that case we iterate over the reversed label list
    List<LLabel> effectiveLabels = labels;
    if (layoutDirection == Direction.UP) {
        effectiveLabels = Lists.reverse(effectiveLabels);
    }
    for (LLabel label : effectiveLabels) {
        label.getPosition().x = labelPos.x;
        if (inline) {
            label.getPosition().y = labelPos.y + (labelSpace.y - label.getSize().y) / 2;
        } else if (leftAligned) {
            label.getPosition().y = labelPos.y;
        } else {
            label.getPosition().y = labelPos.y + labelSpace.y - label.getSize().y;
        }
        labelPos.x += label.getSize().x + labelSpacing;
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel)

Example 30 with LLabel

use of org.eclipse.elk.alg.layered.graph.LLabel 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();
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) Direction(org.eclipse.elk.core.options.Direction) Layer(org.eclipse.elk.alg.layered.graph.Layer)

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