Search in sources :

Example 71 with LEdge

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

the class NodePromotion method promoteNode.

/**
 * Node promotion heuristic of the paper. Works on an array of integers which represents the
 * nodes and their position within the layers to avoid difficulties while creating and deleting
 * new layers over the course of the discarded promotions.
 *
 * @param node
 *            Node that shall be promoted.
 * @return A Pair consisting of an Integer and a Boolean.
 *         <ol>
 *         <li>The Integer is the estimated difference of dummy nodes after applying the node
 *         promotion. A negative value indicates a reduction of dummy nodes.</li>
 *         <li>The Boolean gives information about whether the maximal accepted width has been
 *         exceeded while promoting the given node or not.</li>
 *         </ol>
 */
private Pair<Integer, Boolean> promoteNode(final LNode node) {
    boolean maxWidthNotExceeded = true;
    int dummydiff = 0;
    int nodeLayerPos = layers[node.id];
    double nodeSize = node.getSize().y + nodeSizeAffix;
    int dummiesBuilt = degreeDiff[node.id][2];
    // Calculating the current width of the layer the node came from by subtracting its size
    // from the size of this layer and adding its outgoing edges to this layer because of the
    // then resulting new dummy nodes.
    currentWidth.set(nodeLayerPos, currentWidth.get(nodeLayerPos) - 1 + dummiesBuilt);
    currentWidthPixel.set(nodeLayerPos, currentWidthPixel.get(nodeLayerPos) - nodeSize + dummiesBuilt * dummySize);
    // Calculate index of the layer for the promoted node.
    nodeLayerPos++;
    if (nodeLayerPos >= maxHeight) {
        maxHeight++;
        currentWidth.add(1);
        currentWidthPixel.add(nodeSize);
    } else {
        // Calculating the current width of the layer the node is promoted to by adding its size
        // to the size of this layer and subtracting its incoming edges to this layer due to the
        // resulting potentially reduced dummy nodes. If it's a new layer only the size itself will
        // be added to it.
        int dummiesReduced = degreeDiff[node.id][1];
        currentWidth.set(nodeLayerPos, currentWidth.get(nodeLayerPos) + 1 - dummiesReduced);
        currentWidthPixel.set(nodeLayerPos, currentWidthPixel.get(nodeLayerPos) + nodeSize - dummiesReduced * dummySize);
    }
    // so, the promotion will not be applied.
    if ((promotionStrategy == NodePromotionStrategy.NIKOLOV && (currentWidth.get(nodeLayerPos) > maxWidth || currentWidth.get(nodeLayerPos - 1) > maxWidth)) || (promotionStrategy == NodePromotionStrategy.NIKOLOV_PIXEL && (currentWidthPixel.get(nodeLayerPos) > maxWidthPixel || currentWidthPixel.get(nodeLayerPos - 1) > maxWidthPixel))) {
        maxWidthNotExceeded = false;
    }
    // neighboring layer recursively and calculating the difference of dummy nodes.
    for (LEdge edge : node.getIncomingEdges()) {
        LNode masterNode = edge.getSource().getNode();
        if (layers[masterNode.id] == nodeLayerPos) {
            Pair<Integer, Boolean> promotion = promoteNode(masterNode);
            dummydiff = dummydiff + promotion.getFirst();
            maxWidthNotExceeded = maxWidthNotExceeded && promotion.getSecond();
        }
    }
    layers[node.id] = nodeLayerPos;
    dummydiff = dummydiff + degreeDiff[node.id][0];
    return new Pair<Integer, Boolean>(dummydiff, maxWidthNotExceeded);
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LNode(org.eclipse.elk.alg.layered.graph.LNode) Pair(org.eclipse.elk.core.util.Pair)

Example 72 with LEdge

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

the class NorthSouthPortPostprocessor method processSelfLoop.

/**
 * Reroutes and reconnects the self-loop edge represented by the given dummy.
 *
 * @param dummy the dummy representing the self-loop edge.
 */
private void processSelfLoop(final LNode dummy) {
    // Get the edge and the ports it was originally connected to
    LEdge selfLoop = (LEdge) dummy.getProperty(InternalProperties.ORIGIN);
    LPort inputPort = dummy.getPorts(PortSide.WEST).iterator().next();
    LPort outputPort = dummy.getPorts(PortSide.EAST).iterator().next();
    LPort originInputPort = (LPort) inputPort.getProperty(InternalProperties.ORIGIN);
    LPort originOutputPort = (LPort) outputPort.getProperty(InternalProperties.ORIGIN);
    // Reconnect the edge
    selfLoop.setSource(originOutputPort);
    selfLoop.setTarget(originInputPort);
    // Add two bend points
    KVector bendPoint = new KVector(outputPort.getNode().getPosition());
    bendPoint.x = originOutputPort.getAbsoluteAnchor().x;
    selfLoop.getBendPoints().add(bendPoint);
    bendPoint = new KVector(inputPort.getNode().getPosition());
    bendPoint.x = originInputPort.getAbsoluteAnchor().x;
    selfLoop.getBendPoints().add(bendPoint);
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LPort(org.eclipse.elk.alg.layered.graph.LPort) KVector(org.eclipse.elk.core.math.KVector)

Example 73 with LEdge

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

the class BreakingPointProcessor method performWrapping.

/**
 * Main wrapping procedure, placing the determined chunks one below the other.
 */
private void performWrapping(final LGraph graph) {
    final List<Layer> layers = graph.getLayers();
    final ListIterator<Layer> layerIt = layers.listIterator();
    // add initial empty layer to account for break point start dummies
    layerIt.add(new Layer(graph));
    // iterate the layers from left to right
    // as soon as a layer with a BREAKING POINT start dummy is encountered,
    // the nodes of the next layer should be moved to the very first layer
    // consequently 'wrapping' the graph
    boolean reverse = false;
    int idx = 1;
    while (layerIt.hasNext()) {
        Layer layer = layerIt.next();
        Layer newLayer = layers.get(idx);
        List<LNode> nodesToMove = Lists.newArrayList(layer.getNodes());
        // remember an offset used for adding in-layer dummies later
        int offset = nodesToMove.size();
        // move the nodes to their new layer
        for (LNode n : nodesToMove) {
            n.setLayer(newLayer);
        }
        if (reverse) {
            // important to introduce the chains of long edge dummies in reversed order
            for (LNode n : Lists.reverse(nodesToMove)) {
                for (LEdge e : Lists.newArrayList(n.getIncomingEdges())) {
                    // reverse the edge
                    e.reverse(graph, true);
                    graph.setProperty(InternalProperties.CYCLIC, true);
                    // insert proper dummy nodes for the newly created long edge
                    List<LEdge> dummyEdges = CuttingUtils.insertDummies(graph, e, offset);
                    // ameliorate breaking point info
                    BPInfo bpi = n.getProperty(InternalProperties.BREAKING_POINT_INFO);
                    LEdge startInLayerEdge = dummyEdges.get(dummyEdges.size() - 1);
                    bpi.startInLayerDummy = startInLayerEdge.getSource().getNode();
                    bpi.startInLayerEdge = startInLayerEdge;
                    bpi.endInLayerDummy = e.getTarget().getNode();
                    bpi.endInLayerEdge = e;
                }
            }
            reverse = false;
        } else {
            if (!nodesToMove.isEmpty()) {
                LNode aNode = nodesToMove.get(0);
                if (aNode.getType() == NodeType.BREAKING_POINT) {
                    // next layer should be moved (it contains the breaking point end dummies)
                    reverse = true;
                    // start moving nodes to the very first layer
                    idx = -1;
                }
            }
        }
        idx++;
    }
    // remove old layers that are now empty
    ListIterator<Layer> it = graph.getLayers().listIterator();
    while (it.hasNext()) {
        Layer l = it.next();
        if (l.getNodes().isEmpty()) {
            it.remove();
        }
    }
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) BPInfo(org.eclipse.elk.alg.layered.intermediate.wrapping.BreakingPointInserter.BPInfo) LNode(org.eclipse.elk.alg.layered.graph.LNode) Layer(org.eclipse.elk.alg.layered.graph.Layer)

Example 74 with LEdge

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

the class BreakingPointRemover method remove.

private void remove(final LGraph graph, final BPInfo bpi) {
    // assemble the new edge route
    KVectorChain newBends = new KVectorChain();
    // depending on the edge routing style we have to act differently
    switch(edgeRouting) {
        // so far, only the intermediate nubsplines have been attached via properties
        case SPLINES:
            // gather the computed spline information
            List<SplineSegment> s1 = bpi.nodeStartEdge.getProperty(InternalProperties.SPLINE_ROUTE_START);
            List<SplineSegment> s2 = bpi.startEndEdge.getProperty(InternalProperties.SPLINE_ROUTE_START);
            List<SplineSegment> s3 = bpi.originalEdge.getProperty(InternalProperties.SPLINE_ROUTE_START);
            List<LEdge> e1 = bpi.nodeStartEdge.getProperty(InternalProperties.SPLINE_EDGE_CHAIN);
            List<LEdge> e2 = bpi.startEndEdge.getProperty(InternalProperties.SPLINE_EDGE_CHAIN);
            List<LEdge> e3 = bpi.originalEdge.getProperty(InternalProperties.SPLINE_EDGE_CHAIN);
            // join them (... and remember to reverse some of the segments)
            List<SplineSegment> joinedSegments = Lists.newArrayList();
            joinedSegments.addAll(s1);
            s2.forEach(s -> s.inverseOrder = true);
            joinedSegments.addAll(Lists.reverse(s2));
            joinedSegments.addAll(s3);
            List<LEdge> joinedEdges = Lists.newArrayList();
            joinedEdges.addAll(e1);
            joinedEdges.addAll(Lists.reverse(e2));
            joinedEdges.addAll(e3);
            // transfer the information to the original edge
            bpi.originalEdge.setProperty(InternalProperties.SPLINE_ROUTE_START, joinedSegments);
            bpi.originalEdge.setProperty(InternalProperties.SPLINE_EDGE_CHAIN, joinedEdges);
            bpi.originalEdge.setProperty(InternalProperties.SPLINE_SURVIVING_EDGE, bpi.originalEdge);
            // cleanup
            bpi.nodeStartEdge.setProperty(InternalProperties.SPLINE_ROUTE_START, null);
            bpi.nodeStartEdge.setProperty(InternalProperties.SPLINE_EDGE_CHAIN, null);
            bpi.startEndEdge.setProperty(InternalProperties.SPLINE_ROUTE_START, null);
            bpi.startEndEdge.setProperty(InternalProperties.SPLINE_EDGE_CHAIN, null);
            break;
        // note that the positions of bpi.start and bpi.end must be added as bend points
        case POLYLINE:
            newBends.addAll(bpi.nodeStartEdge.getBendPoints());
            newBends.add(bpi.start.getPosition());
            newBends.addAll(Lists.reverse(bpi.startEndEdge.getBendPoints()));
            newBends.add(bpi.end.getPosition());
            newBends.addAll(bpi.originalEdge.getBendPoints());
            break;
        // of bpi.start and bpi.end can be dropped since they lie on a straight line
        default:
            // ORTHOGONAL
            newBends.addAll(bpi.nodeStartEdge.getBendPoints());
            newBends.addAll(Lists.reverse(bpi.startEndEdge.getBendPoints()));
            newBends.addAll(bpi.originalEdge.getBendPoints());
    }
    // restore original edge
    bpi.originalEdge.getBendPoints().clear();
    bpi.originalEdge.getBendPoints().addAll(newBends);
    bpi.originalEdge.setSource(bpi.nodeStartEdge.getSource());
    // collect any created junction points (order can be arbitrary)
    KVectorChain junctionPointsOne = bpi.nodeStartEdge.getProperty(LayeredOptions.JUNCTION_POINTS);
    KVectorChain junctionPointsTwo = bpi.startEndEdge.getProperty(LayeredOptions.JUNCTION_POINTS);
    KVectorChain junctionPointsThree = bpi.originalEdge.getProperty(LayeredOptions.JUNCTION_POINTS);
    if (junctionPointsOne != null || junctionPointsTwo != null || junctionPointsThree != null) {
        KVectorChain newJunctionPoints = new KVectorChain();
        addNullSafe(newJunctionPoints, junctionPointsThree);
        addNullSafe(newJunctionPoints, junctionPointsTwo);
        addNullSafe(newJunctionPoints, junctionPointsOne);
        bpi.originalEdge.setProperty(LayeredOptions.JUNCTION_POINTS, newJunctionPoints);
    }
    // remove all the dummy stuff
    bpi.startEndEdge.setSource(null);
    bpi.startEndEdge.setTarget(null);
    bpi.nodeStartEdge.setSource(null);
    bpi.nodeStartEdge.setTarget(null);
    bpi.end.setLayer(null);
    bpi.start.setLayer(null);
    if (bpi.prev != null) {
        remove(graph, bpi.prev);
    }
}
Also used : KVectorChain(org.eclipse.elk.core.math.KVectorChain) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) SplineSegment(org.eclipse.elk.alg.layered.p5edges.splines.SplineSegment)

Example 75 with LEdge

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

the class NorthSouthPortPreprocessor method createDummyNode.

/**
 * Creates a dummy node for the given ports. Edges going into {@code inPort} are rerouted to the
 * dummy node's input port. Edges leaving the {@code outPort} are rerouted to the dummy node's
 * output port. Both arguments may refer to the same port. The dummy's port have their
 * {@code ORIGIN} property set to the port whose edges have been rerouted to them.
 *
 * @param layeredGraph
 *            the layered graph.
 * @param inPort
 *            the input port whose edges to reroute. May be {@code null}.
 * @param outPort
 *            the output port whose edges to reroute. May be {@code null}.
 * @param dummyNodes
 *            list the created dummy node should be added to.
 * @return the created dummy node.
 */
private LNode createDummyNode(final LGraph layeredGraph, final LPort inPort, final LPort outPort, final List<LNode> dummyNodes) {
    LNode dummy = new LNode(layeredGraph);
    dummy.setType(NodeType.NORTH_SOUTH_PORT);
    dummy.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS);
    int crossingHint = 0;
    // Input port
    if (inPort != null) {
        // The port is expected to have edges connected to it
        assert !(inPort.getIncomingEdges().isEmpty() && inPort.getOutgoingEdges().isEmpty());
        LPort dummyInputPort = new LPort();
        dummyInputPort.setProperty(InternalProperties.ORIGIN, inPort);
        dummy.setProperty(InternalProperties.ORIGIN, inPort.getNode());
        dummyInputPort.setSide(PortSide.WEST);
        dummyInputPort.setNode(dummy);
        // Reroute edges
        LEdge[] edgeArray = LGraphUtil.toEdgeArray(inPort.getIncomingEdges());
        for (LEdge edge : edgeArray) {
            edge.setTarget(dummyInputPort);
        }
        // Make sure the inPort knows about the dummy node
        inPort.setProperty(InternalProperties.PORT_DUMMY, dummy);
        crossingHint++;
    }
    // Output port
    if (outPort != null) {
        // The port is expected to have edges connected to it
        assert !(outPort.getIncomingEdges().isEmpty() && outPort.getOutgoingEdges().isEmpty());
        LPort dummyOutputPort = new LPort();
        dummy.setProperty(InternalProperties.ORIGIN, outPort.getNode());
        dummyOutputPort.setProperty(InternalProperties.ORIGIN, outPort);
        dummyOutputPort.setSide(PortSide.EAST);
        dummyOutputPort.setNode(dummy);
        // Reroute edges
        LEdge[] edgeArray = LGraphUtil.toEdgeArray(outPort.getOutgoingEdges());
        for (LEdge edge : edgeArray) {
            edge.setSource(dummyOutputPort);
        }
        // Make sure the outPort knows about the dummy node
        outPort.setProperty(InternalProperties.PORT_DUMMY, dummy);
        crossingHint++;
    }
    // Set the crossing hint used for cross counting later
    dummy.setProperty(InternalProperties.CROSSING_HINT, crossingHint);
    dummyNodes.add(dummy);
    return dummy;
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode)

Aggregations

LEdge (org.eclipse.elk.alg.layered.graph.LEdge)148 LNode (org.eclipse.elk.alg.layered.graph.LNode)107 LPort (org.eclipse.elk.alg.layered.graph.LPort)80 Layer (org.eclipse.elk.alg.layered.graph.Layer)41 KVector (org.eclipse.elk.core.math.KVector)34 KVectorChain (org.eclipse.elk.core.math.KVectorChain)20 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)17 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)16 PortSide (org.eclipse.elk.core.options.PortSide)11 ArrayList (java.util.ArrayList)9 List (java.util.List)9 InternalProperties (org.eclipse.elk.alg.layered.options.InternalProperties)8 Set (java.util.Set)7 LayeredOptions (org.eclipse.elk.alg.layered.options.LayeredOptions)7 Map (java.util.Map)6 IElkProgressMonitor (org.eclipse.elk.core.util.IElkProgressMonitor)6 Lists (com.google.common.collect.Lists)5 Iterator (java.util.Iterator)5 ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)5 Pair (org.eclipse.elk.core.util.Pair)5