Search in sources :

Example 91 with LEdge

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

the class LinearSegmentsNodePlacer method postProcess.

// /////////////////////////////////////////////////////////////////////////////
// Post Processing for Correction
/**
 * Post-process the balanced placement by moving linear segments where obvious improvements can
 * be made.
 *
 * @param layeredGraph
 *            the layered graph
 */
private void postProcess(final LGraph layeredGraph) {
    // process each linear segment independently
    for (LinearSegment segment : linearSegments) {
        double minRoomAbove = Integer.MAX_VALUE, minRoomBelow = Integer.MAX_VALUE;
        for (LNode node : segment.nodes) {
            double roomAbove, roomBelow;
            int index = node.getIndex();
            // determine the amount by which the linear segment can be moved up without overlap
            if (index > 0) {
                LNode neighbor = node.getLayer().getNodes().get(index - 1);
                double spacing = spacings.getVerticalSpacing(node, neighbor);
                roomAbove = node.getPosition().y - node.getMargin().top - (neighbor.getPosition().y + neighbor.getSize().y + neighbor.getMargin().bottom + spacing);
            } else {
                roomAbove = node.getPosition().y - node.getMargin().top;
            }
            minRoomAbove = Math.min(roomAbove, minRoomAbove);
            // overlap
            if (index < node.getLayer().getNodes().size() - 1) {
                LNode neighbor = node.getLayer().getNodes().get(index + 1);
                double spacing = spacings.getVerticalSpacing(node, neighbor);
                roomBelow = neighbor.getPosition().y - neighbor.getMargin().top - (node.getPosition().y + node.getSize().y + node.getMargin().bottom + spacing);
            } else {
                roomBelow = 2 * node.getPosition().y;
            }
            minRoomBelow = Math.min(roomBelow, minRoomBelow);
        }
        double minDisplacement = Integer.MAX_VALUE;
        boolean foundPlace = false;
        // determine the minimal displacement that would make one incoming edge straight
        LNode firstNode = segment.nodes.get(0);
        for (LPort target : firstNode.getPorts()) {
            double pos = firstNode.getPosition().y + target.getPosition().y + target.getAnchor().y;
            for (LEdge edge : target.getIncomingEdges()) {
                LPort source = edge.getSource();
                double d = source.getNode().getPosition().y + source.getPosition().y + source.getAnchor().y - pos;
                if (Math.abs(d) < Math.abs(minDisplacement) && Math.abs(d) < (d < 0 ? minRoomAbove : minRoomBelow)) {
                    minDisplacement = d;
                    foundPlace = true;
                }
            }
        }
        // determine the minimal displacement that would make one outgoing edge straight
        LNode lastNode = segment.nodes.get(segment.nodes.size() - 1);
        for (LPort source : lastNode.getPorts()) {
            double pos = lastNode.getPosition().y + source.getPosition().y + source.getAnchor().y;
            for (LEdge edge : source.getOutgoingEdges()) {
                LPort target = edge.getTarget();
                double d = target.getNode().getPosition().y + target.getPosition().y + target.getAnchor().y - pos;
                if (Math.abs(d) < Math.abs(minDisplacement) && Math.abs(d) < (d < 0 ? minRoomAbove : minRoomBelow)) {
                    minDisplacement = d;
                    foundPlace = true;
                }
            }
        }
        // if such a displacement could be found, apply it to the whole linear segment
        if (foundPlace && minDisplacement != 0) {
            for (LNode node : segment.nodes) {
                node.getPosition().y += minDisplacement;
            }
        }
    }
}
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)

Example 92 with LEdge

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

the class LinearSegmentsNodePlacer method sortLinearSegments.

// /////////////////////////////////////////////////////////////////////////////
// Linear Segments Creation
/**
 * Sorts the linear segments of the given layered graph by finding a topological ordering in the
 * corresponding segment ordering graph.
 *
 * @param layeredGraph
 *            layered graph to process
 * @param monitor
 *            our progress monitor.
 * @return a sorted array of linear segments
 */
private LinearSegment[] sortLinearSegments(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
    // set the identifier and input / output priority for all nodes
    List<LinearSegment> segmentList = Lists.newArrayList();
    for (Layer layer : layeredGraph) {
        for (LNode node : layer) {
            node.id = -1;
            int inprio = Integer.MIN_VALUE, outprio = Integer.MIN_VALUE;
            for (LPort port : node.getPorts()) {
                for (LEdge edge : port.getIncomingEdges()) {
                    int prio = edge.getProperty(LayeredOptions.PRIORITY_STRAIGHTNESS);
                    inprio = Math.max(inprio, prio);
                }
                for (LEdge edge : port.getOutgoingEdges()) {
                    int prio = edge.getProperty(LayeredOptions.PRIORITY_STRAIGHTNESS);
                    outprio = Math.max(outprio, prio);
                }
            }
            node.setProperty(INPUT_PRIO, inprio);
            node.setProperty(OUTPUT_PRIO, outprio);
        }
    }
    // create linear segments for the layered graph, ignoring odd port side dummies
    int nextLinearSegmentID = 0;
    for (Layer layer : layeredGraph) {
        for (LNode node : layer) {
            // to be != -1.
            if (node.id < 0) {
                LinearSegment segment = new LinearSegment();
                segment.id = nextLinearSegmentID++;
                fillSegment(node, segment);
                segmentList.add(segment);
            }
        }
    }
    // create and initialize segment ordering graph
    List<List<LinearSegment>> outgoingList = Lists.newArrayListWithCapacity(segmentList.size());
    List<Integer> incomingCountList = Lists.newArrayListWithCapacity(segmentList.size());
    for (int i = 0; i < segmentList.size(); i++) {
        outgoingList.add(new ArrayList<LinearSegment>());
        incomingCountList.add(0);
    }
    // create edges for the segment ordering graph
    createDependencyGraphEdges(monitor, layeredGraph, segmentList, outgoingList, incomingCountList);
    // turn lists into arrays
    LinearSegment[] segments = segmentList.toArray(new LinearSegment[segmentList.size()]);
    @SuppressWarnings("unchecked") List<LinearSegment>[] outgoing = outgoingList.toArray(new List[outgoingList.size()]);
    int[] incomingCount = new int[incomingCountList.size()];
    for (int i = 0; i < incomingCount.length; i++) {
        incomingCount[i] = incomingCountList.get(i);
    }
    // gather the sources of the segment ordering graph
    int nextRank = 0;
    List<LinearSegment> noIncoming = Lists.newArrayList();
    for (int i = 0; i < segments.length; i++) {
        if (incomingCount[i] == 0) {
            noIncoming.add(segments[i]);
        }
    }
    // find a topological ordering of the segment ordering graph
    int[] newRanks = new int[segments.length];
    while (!noIncoming.isEmpty()) {
        LinearSegment segment = noIncoming.remove(0);
        newRanks[segment.id] = nextRank++;
        while (!outgoing[segment.id].isEmpty()) {
            LinearSegment target = outgoing[segment.id].remove(0);
            incomingCount[target.id]--;
            if (incomingCount[target.id] == 0) {
                noIncoming.add(target);
            }
        }
    }
    // apply the new ordering to the array of linear segments
    linearSegments = new LinearSegment[segments.length];
    for (int i = 0; i < segments.length; i++) {
        assert outgoing[i].isEmpty();
        LinearSegment ls = segments[i];
        int rank = newRanks[i];
        linearSegments[rank] = ls;
        ls.id = rank;
        for (LNode node : ls.nodes) {
            node.id = rank;
        }
    }
    return linearSegments;
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) Layer(org.eclipse.elk.alg.layered.graph.Layer) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) ArrayList(java.util.ArrayList) List(java.util.List)

Example 93 with LEdge

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

the class CrossingsCounter method countCrossingsOnPorts.

private int countCrossingsOnPorts(final Iterable<LPort> ports) {
    int crossings = 0;
    for (LPort port : ports) {
        indexTree.removeAll(positionOf(port));
        // First get crossings for all edges.
        for (LEdge edge : port.getConnectedEdges()) {
            int endPosition = positionOf(otherEndOf(edge, port));
            if (endPosition > positionOf(port)) {
                crossings += indexTree.rank(endPosition);
                ends.push(endPosition);
            }
        }
        // Then add end points.
        while (!ends.isEmpty()) {
            indexTree.add(ends.pop());
        }
    }
    return crossings;
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LPort(org.eclipse.elk.alg.layered.graph.LPort)

Example 94 with LEdge

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

the class CrossingsCounter method countInLayerCrossingsOnPorts.

private int countInLayerCrossingsOnPorts(final Iterable<LPort> ports) {
    int crossings = 0;
    for (LPort port : ports) {
        indexTree.removeAll(positionOf(port));
        int numBetweenLayerEdges = 0;
        // First get crossings for all edges.
        for (LEdge edge : port.getConnectedEdges()) {
            if (isInLayer(edge)) {
                int endPosition = positionOf(otherEndOf(edge, port));
                if (endPosition > positionOf(port)) {
                    crossings += indexTree.rank(endPosition);
                    ends.push(endPosition);
                }
            } else {
                numBetweenLayerEdges++;
            }
        }
        crossings += indexTree.size() * numBetweenLayerEdges;
        // Then add end points.
        while (!ends.isEmpty()) {
            indexTree.add(ends.pop());
        }
    }
    return crossings;
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LPort(org.eclipse.elk.alg.layered.graph.LPort)

Example 95 with LEdge

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

the class HyperedgeCrossingsCounter method countCrossings.

/**
 * Special crossings counting method for hyperedges. See
 * <ul>
 *   <li>M. Sp&ouml;nemann, C. D. Schulze, U. R&uuml;egg, R. von Hanxleden.
 *     Counting crossings for layered hypergraphs, In <i>DIAGRAMS 2014</i>,
 *     volume 8578 of LNAI, Springer, 2014.</li>
 * </ul>
 *
 * @param leftLayer
 *            the left layer
 * @param rightLayer
 *            the right layer
 * @return the number of edge crossings
 */
// SUPPRESS CHECKSTYLE NEXT 1 MethodLength
public int countCrossings(final LNode[] leftLayer, final LNode[] rightLayer) {
    // Assign index values to the ports of the left layer
    int sourceCount = 0;
    for (LNode node : leftLayer) {
        // Assign index values in the order north - east - south - west
        for (LPort port : node.getPorts()) {
            int portEdges = 0;
            for (LEdge edge : port.getOutgoingEdges()) {
                if (node.getLayer() != edge.getTarget().getNode().getLayer()) {
                    portEdges++;
                }
            }
            if (portEdges > 0) {
                portPos[port.id] = sourceCount++;
            }
        }
    }
    // Assign index values to the ports of the right layer
    int targetCount = 0;
    for (LNode node : rightLayer) {
        // Determine how many input ports there are on the north side
        // (note that the standard port order is north - east - south - west)
        int northInputPorts = 0;
        for (LPort port : node.getPorts()) {
            if (port.getSide() == PortSide.NORTH) {
                for (LEdge edge : port.getIncomingEdges()) {
                    if (node.getLayer() != edge.getSource().getNode().getLayer()) {
                        northInputPorts++;
                        break;
                    }
                }
            } else {
                break;
            }
        }
        // Assign index values in the order north - west - south - east
        int otherInputPorts = 0;
        ListIterator<LPort> portIter = node.getPorts().listIterator(node.getPorts().size());
        while (portIter.hasPrevious()) {
            LPort port = portIter.previous();
            int portEdges = 0;
            for (LEdge edge : port.getIncomingEdges()) {
                if (node.getLayer() != edge.getSource().getNode().getLayer()) {
                    portEdges++;
                }
            }
            if (portEdges > 0) {
                if (port.getSide() == PortSide.NORTH) {
                    portPos[port.id] = targetCount;
                    targetCount++;
                } else {
                    portPos[port.id] = targetCount + northInputPorts + otherInputPorts;
                    otherInputPorts++;
                }
            }
        }
        targetCount += otherInputPorts;
    }
    // Gather hyperedges
    Map<LPort, Hyperedge> port2HyperedgeMap = Maps.newHashMap();
    Set<Hyperedge> hyperedgeSet = Sets.newLinkedHashSet();
    for (LNode node : leftLayer) {
        for (LPort sourcePort : node.getPorts()) {
            for (LEdge edge : sourcePort.getOutgoingEdges()) {
                LPort targetPort = edge.getTarget();
                if (node.getLayer() != targetPort.getNode().getLayer()) {
                    Hyperedge sourceHE = port2HyperedgeMap.get(sourcePort);
                    Hyperedge targetHE = port2HyperedgeMap.get(targetPort);
                    if (sourceHE == null && targetHE == null) {
                        Hyperedge hyperedge = new Hyperedge();
                        hyperedgeSet.add(hyperedge);
                        hyperedge.edges.add(edge);
                        hyperedge.ports.add(sourcePort);
                        port2HyperedgeMap.put(sourcePort, hyperedge);
                        hyperedge.ports.add(targetPort);
                        port2HyperedgeMap.put(targetPort, hyperedge);
                    } else if (sourceHE == null) {
                        targetHE.edges.add(edge);
                        targetHE.ports.add(sourcePort);
                        port2HyperedgeMap.put(sourcePort, targetHE);
                    } else if (targetHE == null) {
                        sourceHE.edges.add(edge);
                        sourceHE.ports.add(targetPort);
                        port2HyperedgeMap.put(targetPort, sourceHE);
                    } else if (sourceHE == targetHE) {
                        sourceHE.edges.add(edge);
                    } else {
                        sourceHE.edges.add(edge);
                        for (LPort p : targetHE.ports) {
                            port2HyperedgeMap.put(p, sourceHE);
                        }
                        sourceHE.edges.addAll(targetHE.edges);
                        sourceHE.ports.addAll(targetHE.ports);
                        hyperedgeSet.remove(targetHE);
                    }
                }
            }
        }
    }
    // Determine top and bottom positions for each hyperedge
    Hyperedge[] hyperedges = hyperedgeSet.toArray(new Hyperedge[hyperedgeSet.size()]);
    Layer leftLayerRef = leftLayer[0].getLayer();
    Layer rightLayerRef = rightLayer[0].getLayer();
    for (Hyperedge he : hyperedges) {
        he.upperLeft = sourceCount;
        he.upperRight = targetCount;
        for (LPort port : he.ports) {
            int pos = portPos[port.id];
            if (port.getNode().getLayer() == leftLayerRef) {
                if (pos < he.upperLeft) {
                    he.upperLeft = pos;
                }
                if (pos > he.lowerLeft) {
                    he.lowerLeft = pos;
                }
            } else if (port.getNode().getLayer() == rightLayerRef) {
                if (pos < he.upperRight) {
                    he.upperRight = pos;
                }
                if (pos > he.lowerRight) {
                    he.lowerRight = pos;
                }
            }
        }
    }
    // Determine the sequence of edge target positions sorted by source and target index
    Arrays.sort(hyperedges);
    int[] southSequence = new int[hyperedges.length];
    int[] compressDeltas = new int[targetCount + 1];
    for (int i = 0; i < hyperedges.length; i++) {
        southSequence[i] = hyperedges[i].upperRight;
        compressDeltas[southSequence[i]] = 1;
    }
    int delta = 0;
    for (int i = 0; i < compressDeltas.length; i++) {
        if (compressDeltas[i] == 1) {
            compressDeltas[i] = delta;
        } else {
            delta--;
        }
    }
    int q = 0;
    for (int i = 0; i < southSequence.length; i++) {
        southSequence[i] += compressDeltas[southSequence[i]];
        q = Math.max(q, southSequence[i] + 1);
    }
    // Build the accumulator tree
    int firstIndex = 1;
    while (firstIndex < q) {
        firstIndex *= 2;
    }
    int treeSize = 2 * firstIndex - 1;
    firstIndex -= 1;
    int[] tree = new int[treeSize];
    // Count the straight-line crossings of the topmost edges
    int crossings = 0;
    for (int k = 0; k < southSequence.length; k++) {
        int index = southSequence[k] + firstIndex;
        tree[index]++;
        while (index > 0) {
            if (index % 2 > 0) {
                crossings += tree[index + 1];
            }
            index = (index - 1) / 2;
            tree[index]++;
        }
    }
    // Create corners for the left side
    HyperedgeCorner[] leftCorners = new HyperedgeCorner[hyperedges.length * 2];
    for (int i = 0; i < hyperedges.length; i++) {
        leftCorners[2 * i] = new HyperedgeCorner(hyperedges[i], hyperedges[i].upperLeft, hyperedges[i].lowerLeft, HyperedgeCorner.Type.UPPER);
        leftCorners[2 * i + 1] = new HyperedgeCorner(hyperedges[i], hyperedges[i].lowerLeft, hyperedges[i].upperLeft, HyperedgeCorner.Type.LOWER);
    }
    Arrays.sort(leftCorners);
    // Count crossings caused by overlapping hyperedge areas on the left side
    int openHyperedges = 0;
    for (int i = 0; i < leftCorners.length; i++) {
        switch(leftCorners[i].type) {
            case UPPER:
                openHyperedges++;
                break;
            case LOWER:
                openHyperedges--;
                crossings += openHyperedges;
                break;
        }
    }
    // Create corners for the right side
    HyperedgeCorner[] rightCorners = new HyperedgeCorner[hyperedges.length * 2];
    for (int i = 0; i < hyperedges.length; i++) {
        rightCorners[2 * i] = new HyperedgeCorner(hyperedges[i], hyperedges[i].upperRight, hyperedges[i].lowerRight, HyperedgeCorner.Type.UPPER);
        rightCorners[2 * i + 1] = new HyperedgeCorner(hyperedges[i], hyperedges[i].lowerRight, hyperedges[i].upperRight, HyperedgeCorner.Type.LOWER);
    }
    Arrays.sort(rightCorners);
    // Count crossings caused by overlapping hyperedge areas on the right side
    openHyperedges = 0;
    for (int i = 0; i < rightCorners.length; i++) {
        switch(rightCorners[i].type) {
            case UPPER:
                openHyperedges++;
                break;
            case LOWER:
                openHyperedges--;
                crossings += openHyperedges;
                break;
        }
    }
    return crossings;
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) Layer(org.eclipse.elk.alg.layered.graph.Layer) 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