Search in sources :

Example 96 with LNode

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

the class InteractiveLayerer method process.

@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
    monitor.begin("Interactive node layering", 1);
    // create layers with a start and an end position, merging when they overlap with others
    List<LayerSpan> currentSpans = Lists.newArrayList();
    for (LNode node : layeredGraph.getLayerlessNodes()) {
        double minx = node.getPosition().x;
        double maxx = minx + node.getSize().x;
        // for the following code we have to guarantee that every node has a width,
        // which, for instance, might not be the case for external dummy nodes
        maxx = Math.max(minx + 1, maxx);
        // look for a position in the sorted list where the node can be inserted
        ListIterator<LayerSpan> spanIter = currentSpans.listIterator();
        LayerSpan foundSpan = null;
        while (spanIter.hasNext()) {
            LayerSpan span = spanIter.next();
            if (span.start >= maxx) {
                // the next layer span is further right, so insert the node here
                spanIter.previous();
                break;
            } else if (span.end > minx) {
                // the layer span has an intersection with the node
                if (foundSpan == null) {
                    // add the node to the current layer span
                    span.nodes.add(node);
                    span.start = Math.min(span.start, minx);
                    span.end = Math.max(span.end, maxx);
                    foundSpan = span;
                } else {
                    // merge the previously found layer span with the current one
                    foundSpan.nodes.addAll(span.nodes);
                    foundSpan.end = Math.max(foundSpan.end, span.end);
                    spanIter.remove();
                }
            }
        }
        if (foundSpan == null) {
            // no intersecting span was found, so create a new one
            foundSpan = new LayerSpan();
            foundSpan.start = minx;
            foundSpan.end = maxx;
            spanIter.add(foundSpan);
            foundSpan.nodes.add(node);
        }
    }
    // create real layers from the layer spans
    List<Layer> layers = layeredGraph.getLayers();
    int nextIndex = 0;
    for (LayerSpan span : currentSpans) {
        Layer layer = new Layer(layeredGraph);
        layer.id = nextIndex++;
        layers.add(layer);
        for (LNode node : span.nodes) {
            node.setLayer(layer);
            node.id = 0;
        }
    }
    // correct the layering respecting the graph topology, so edges point from left to right
    for (LNode node : layeredGraph.getLayerlessNodes()) {
        if (node.id == 0) {
            checkNode(node, layeredGraph);
        }
    }
    // remove empty layers, which can happen when the layering has to be corrected
    ListIterator<Layer> layerIterator = layers.listIterator();
    while (layerIterator.hasNext()) {
        if (layerIterator.next().getNodes().isEmpty()) {
            layerIterator.remove();
        }
    }
    // clear the list of nodes that have no layer, since now they all have one
    layeredGraph.getLayerlessNodes().clear();
    monitor.done();
}
Also used : LNode(org.eclipse.elk.alg.layered.graph.LNode) Layer(org.eclipse.elk.alg.layered.graph.Layer)

Example 97 with LNode

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

the class SweepCopy method assertCorrectPortSides.

/**
 * Corrects the {@link PortSide} of dummy's origin.
 * @return The {@link LNode} ('origin') whose port {@code dummy} represents.
 */
private LNode assertCorrectPortSides(final LNode dummy) {
    assert dummy.getType() == NodeType.NORTH_SOUTH_PORT;
    LNode origin = dummy.getProperty(InternalProperties.IN_LAYER_LAYOUT_UNIT);
    // a north south port dummy has exactly one port
    List<LPort> dummyPorts = dummy.getPorts();
    LPort dummyPort = dummyPorts.get(0);
    // find the corresponding port on the regular node
    for (LPort port : origin.getPorts()) {
        if (port.equals(dummyPort.getProperty(InternalProperties.ORIGIN))) {
            // switch the port's side if necessary
            if ((port.getSide() == PortSide.NORTH) && (dummy.id > origin.id)) {
                port.setSide(PortSide.SOUTH);
                if (port.isExplicitlySuppliedPortAnchor()) {
                    // Set new coordinates for port anchor since it was switched from NORTH to SOUTH.
                    // The y coordinate is updated by mirroring the y coordinate
                    double portHeight = port.getSize().y;
                    double anchorY = port.getAnchor().y;
                    port.getAnchor().y = portHeight - anchorY;
                }
            } else if ((port.getSide() == PortSide.SOUTH) && (origin.id > dummy.id)) {
                port.setSide(PortSide.NORTH);
                if (port.isExplicitlySuppliedPortAnchor()) {
                    // Set new coordinates for port anchor since it was switched from NORTH to SOUTH.
                    // The y coordinate is updated by mirroring the y coordinate
                    double portHeight = port.getSize().y;
                    double anchorY = port.getAnchor().y;
                    port.getAnchor().y = -(portHeight - anchorY);
                }
            }
            break;
        }
    }
    return origin;
}
Also used : LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode)

Example 98 with LNode

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

the class AllCrossingsCounter method initAtNodeLevel.

@Override
public void initAtNodeLevel(final int l, final int n, final LNode[][] nodeOrder) {
    LNode node = nodeOrder[l][n];
    hasNorthSouthPorts[l] |= node.getType() == NodeType.NORTH_SOUTH_PORT;
}
Also used : LNode(org.eclipse.elk.alg.layered.graph.LNode)

Example 99 with LNode

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

the class CrossingsCounter method initPositionsForNorthSouthCounting.

private List<LPort> initPositionsForNorthSouthCounting(final LNode[] nodes) {
    final List<LPort> ports = Lists.newArrayList();
    final Deque<LNode> stack = new ArrayDeque<>();
    LNode lastLayoutUnit = null;
    int index = 0;
    for (int i = 0; i < nodes.length; ++i) {
        LNode current = nodes[i];
        if (isLayoutUnitChanged(lastLayoutUnit, current)) {
            // work the stack (filled with southern dummies)
            index = emptyStack(stack, ports, STACK_SIDE, index);
        }
        if (current.hasProperty(InternalProperties.IN_LAYER_LAYOUT_UNIT)) {
            lastLayoutUnit = current.getProperty(InternalProperties.IN_LAYER_LAYOUT_UNIT);
        }
        switch(current.getType()) {
            // what we consider normal
            case NORMAL:
                // index the northern ports west-to-east
                for (LPort p : getNorthSouthPortsWithIncidentEdges(current, PortSide.NORTH)) {
                    portPositions[p.id] = index++;
                    ports.add(p);
                }
                // work the stack (filled with northern dummies)
                index = emptyStack(stack, ports, STACK_SIDE, index);
                // index the southern ports in regular clock-wise order
                for (LPort p : getNorthSouthPortsWithIncidentEdges(current, PortSide.SOUTH)) {
                    portPositions[p.id] = index++;
                    ports.add(p);
                }
                break;
            case NORTH_SOUTH_PORT:
                if (!current.getPortSideView(INDEXING_SIDE).isEmpty()) {
                    // should be only one
                    LPort p = current.getPortSideView(INDEXING_SIDE).get(0);
                    portPositions[p.id] = index++;
                    ports.add(p);
                }
                if (!current.getPortSideView(STACK_SIDE).isEmpty()) {
                    stack.push(current);
                }
                break;
            case LONG_EDGE:
                for (LPort p : current.getPortSideView(PortSide.WEST)) {
                    portPositions[p.id] = index++;
                    ports.add(p);
                }
                current.getPortSideView(PortSide.EAST).forEach(p -> stack.push(current));
                break;
            // nothing to do here
            default:
        }
    }
    // are there any southern dummy nodes left on the stack?
    emptyStack(stack, ports, STACK_SIDE, index);
    return ports;
}
Also used : LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) ArrayDeque(java.util.ArrayDeque)

Example 100 with LNode

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

the class CrossingsCounter method countNorthSouthCrossingsOnPorts.

private int countNorthSouthCrossingsOnPorts(final Iterable<LPort> ports) {
    int crossings = 0;
    final List<Pair<LPort, Integer>> targetsAndDegrees = Lists.newArrayList();
    for (LPort port : ports) {
        indexTree.removeAll(positionOf(port));
        targetsAndDegrees.clear();
        // which is a bit tedious since north/south ports have no physical edge within the graph at this point
        switch(port.getNode().getType()) {
            case NORMAL:
                LNode dummy = (LNode) port.getProperty(InternalProperties.PORT_DUMMY);
                // guarded in #initPositionsForNorthSouthCounting(...)
                assert dummy != null;
                // western and eastern
                dummy.getPorts().forEach(p -> targetsAndDegrees.add(Pair.of(p, p.getDegree())));
                break;
            case LONG_EDGE:
                port.getNode().getPorts().stream().filter(p -> p != port).findFirst().ifPresent(p -> targetsAndDegrees.add(Pair.of(p, p.getDegree())));
                break;
            case NORTH_SOUTH_PORT:
                LPort dummyPort = (LPort) port.getProperty(InternalProperties.ORIGIN);
                targetsAndDegrees.add(Pair.of(dummyPort, port.getDegree()));
                break;
        }
        // First get crossings for all edges.
        for (Pair<LPort, Integer> targetAndDegree : targetsAndDegrees) {
            int endPosition = positionOf(targetAndDegree.getFirst());
            if (endPosition > positionOf(port)) {
                crossings += indexTree.rank(endPosition) * targetAndDegree.getSecond();
                ends.push(endPosition);
            }
        }
        // Then add end points.
        while (!ends.isEmpty()) {
            indexTree.add(ends.pop());
        }
    }
    return crossings;
}
Also used : LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) Pair(org.eclipse.elk.core.util.Pair)

Aggregations

LNode (org.eclipse.elk.alg.layered.graph.LNode)471 LPort (org.eclipse.elk.alg.layered.graph.LPort)189 Layer (org.eclipse.elk.alg.layered.graph.Layer)185 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)110 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)91 Test (org.junit.Test)85 KVector (org.eclipse.elk.core.math.KVector)38 PortSide (org.eclipse.elk.core.options.PortSide)28 List (java.util.List)23 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)22 GraphInfoHolder (org.eclipse.elk.alg.layered.p3order.GraphInfoHolder)16 TestAfterProcessor (org.eclipse.elk.alg.test.framework.annotations.TestAfterProcessor)16 KVectorChain (org.eclipse.elk.core.math.KVectorChain)15 NodeType (org.eclipse.elk.alg.layered.graph.LNode.NodeType)14 ArrayList (java.util.ArrayList)13 InternalProperties (org.eclipse.elk.alg.layered.options.InternalProperties)13 LayeredOptions (org.eclipse.elk.alg.layered.options.LayeredOptions)13 PortConstraints (org.eclipse.elk.core.options.PortConstraints)13 Set (java.util.Set)12 CrossingsCounter (org.eclipse.elk.alg.layered.p3order.counting.CrossingsCounter)10