Search in sources :

Example 1 with SelfLoopPort

use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort in project elk by eclipse.

the class SelfLoopPreProcessor method hidePorts.

/**
 * Possibly hides all ports whose only incident edges are self loops. This is only done if port constraints are not
 * at least {@link PortConstraints#FIXED_ORDER}.
 */
private void hidePorts(final SelfLoopHolder slHolder) {
    LNode lNode = slHolder.getLNode();
    LGraph nestedGraph = lNode.getNestedGraph();
    /* There are two cases in which we want to refrain from hiding ports:
         * 1. The port order is already fixed. Then the code that would compute a proper port order won't be confused by
         *    the self-loop ports, so there's no need to hide them.
         * 2. The self loop holder has another graph inside of it which contains external ports. In that case, the
         *    crossing minimization will compute proper port orders. The self loop holder will have the port order
         *    applied and its port constraints set to FIXED_POS, so this is basically the first case with extra steps.
         */
    boolean orderFixed = lNode.getProperty(LayeredOptions.PORT_CONSTRAINTS).isOrderFixed();
    boolean hierarchyMode = nestedGraph != null && nestedGraph.getProperty(InternalProperties.GRAPH_PROPERTIES).contains(GraphProperties.EXTERNAL_PORTS);
    if (orderFixed || hierarchyMode) {
        // No need to hide any ports
        return;
    }
    for (SelfLoopPort slPort : slHolder.getSLPortMap().values()) {
        if (slPort.hadOnlySelfLoops()) {
            // Hide the port
            LPort lPort = slPort.getLPort();
            lPort.setNode(null);
            // Remember that we actually did so
            slPort.setHidden(true);
            slHolder.setPortsHidden(true);
            // run into this case.
            assert lPort.getProperty(InternalProperties.PORT_DUMMY) == null;
        }
    }
}
Also used : LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) SelfLoopPort(org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort) LGraph(org.eclipse.elk.alg.layered.graph.LGraph)

Example 2 with SelfLoopPort

use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort in project elk by eclipse.

the class RoutingDirector method determineFourSideLoopRoutes.

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Route Determination (Four Sides)
/**
 * For four-sided self loops, we have at least one port on every side. If we look at the list of ports, this means
 * that we want to insert a break between some pair of ports adjacent in that list: one will become the leftmost
 * port, and the other will become the rightmost port. What we want to do is find the pair of ports with the maximum
 * number of ports with external connections between them, since that will minimize the number of edge crossings our
 * routing will produce.
 */
private void determineFourSideLoopRoutes(final SelfHyperLoop slLoop) {
    // The self loop ports are sorted by ID
    List<SelfLoopPort> sortedSLPorts = slLoop.getSLPorts();
    SelfLoopHolder slHolder = slLoop.getSLHolder();
    // Go through each pair of adjacent ports and find the one which incurs the highest penalty if we drew an edge
    // between them. That's the pair we want to split the loop at. We start with the uppermost port on the western
    // side and the leftmost on the northern side and then compare successive pairs against those two
    SelfLoopPort worstLeftPort = sortedSLPorts.get(sortedSLPorts.size() - 1);
    SelfLoopPort worstRightPort = sortedSLPorts.get(0);
    int worstPenalty = computeEdgePenalty(slHolder, worstLeftPort, worstRightPort);
    for (int rightPortIndex = 1; rightPortIndex < sortedSLPorts.size(); rightPortIndex++) {
        SelfLoopPort currLeftPort = sortedSLPorts.get(rightPortIndex - 1);
        SelfLoopPort currRightPort = sortedSLPorts.get(rightPortIndex);
        int currPenalty = computeEdgePenalty(slHolder, currLeftPort, currRightPort);
        if (currPenalty > worstPenalty) {
            worstLeftPort = currLeftPort;
            worstRightPort = currRightPort;
            worstPenalty = currPenalty;
        }
    }
    // Since we _don't_ want to draw the self loop between the left and right ports, we switch them here
    slLoop.setLeftmostPort(worstRightPort);
    slLoop.setRightmostPort(worstLeftPort);
}
Also used : SelfLoopHolder(org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopHolder) SelfLoopPort(org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort)

Example 3 with SelfLoopPort

use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort in project elk by eclipse.

the class PortSideAssigner method assignToTarget.

/**
 * Assigns the given self loop to the given target.
 */
private void assignToTarget(final SelfHyperLoop slLoop, final Target target) {
    // Gather the self loop's ports
    List<SelfLoopPort> slPorts = slLoop.getSLPorts();
    // same side anyway, so there's no need for us to sort anything
    if (target.isCornerTarget()) {
        // This will sort the port's original list, but that's okay since it doesn't have any particular order
        // prior to running the PortRestorer
        slPorts.sort((slPort1, slPort2) -> Integer.compare(slPort1.getLPort().getNetFlow(), slPort2.getLPort().getNetFlow()));
    }
    // Assign the first half of the ports to the first side, and the second half to the second side. However, only
    // assign ports that have been hidden and can thus be freely assigned to a side. This could be done way more
    // intelligently, but hopefully bad cases won't be common enough to warrant more effort here.
    int secondHalfStartIndex = slPorts.size() / 2;
    for (int i = 0; i < secondHalfStartIndex; i++) {
        SelfLoopPort slPort = slPorts.get(i);
        if (slPort.isHidden()) {
            slPort.getLPort().setSide(target.firstSide);
        }
    }
    for (int i = secondHalfStartIndex; i < slPorts.size(); i++) {
        SelfLoopPort slPort = slPorts.get(i);
        if (slPort.isHidden()) {
            slPort.getLPort().setSide(target.secondSide);
        }
    }
}
Also used : SelfLoopPort(org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort)

Example 4 with SelfLoopPort

use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort in project elk by eclipse.

the class LabelPlacer method computeCoordinates.

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Coordinate Computation
private void computeCoordinates(final SelfHyperLoop slLoop) {
    // The coordinates really only depend on the alignment since LEFT, CENTER and RIGHT are specific to the north
    // and south sides while TOP is specific to the east and west sides
    SelfHyperLoopLabels slLabels = slLoop.getSLLabels();
    SelfLoopPort alignRef = slLabels.getAlignmentReferenceSLPort();
    KVector size = slLabels.getSize();
    KVector pos = slLabels.getPosition();
    switch(slLabels.getAlignment()) {
        case CENTER:
            pos.x = (slLoop.getSLHolder().getLNode().getSize().x - size.x) / 2;
            break;
        case LEFT:
            pos.x = alignRef.getLPort().getPosition().x + alignRef.getLPort().getAnchor().x;
            break;
        case RIGHT:
            pos.x = alignRef.getLPort().getPosition().x + alignRef.getLPort().getAnchor().x - size.x;
            break;
        case TOP:
            pos.y = alignRef.getLPort().getPosition().y + alignRef.getLPort().getAnchor().y;
            break;
        default:
            assert false;
    }
}
Also used : SelfHyperLoopLabels(org.eclipse.elk.alg.layered.intermediate.loops.SelfHyperLoopLabels) SelfLoopPort(org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort) KVector(org.eclipse.elk.core.math.KVector)

Example 5 with SelfLoopPort

use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort in project elk by eclipse.

the class LabelPlacer method assignOneSidedSimpleSideAndAlignment.

/**
 * Side and alignment assignment for those one-sided self loops where the choice is obvious. This is always the
 * case for eastern and western self loops. For northern and southern self loops, this is the case if they are
 * stacked.
 */
private void assignOneSidedSimpleSideAndAlignment(final SelfHyperLoop slLoop, final PortSide loopSide) {
    switch(loopSide) {
        case EAST:
        case WEST:
            // The alignment will be relative to the topmost port (which must be either the leftmost or the rightmost
            // port)
            SelfLoopPort topmostPort = slLoop.getLeftmostPort();
            if (slLoop.getRightmostPort().getLPort().getPosition().y < topmostPort.getLPort().getPosition().y) {
                topmostPort = slLoop.getRightmostPort();
            }
            assignSideAndAlignment(slLoop, loopSide, Alignment.TOP, topmostPort);
            break;
        case NORTH:
        case SOUTH:
            assignSideAndAlignment(slLoop, loopSide, Alignment.CENTER, null);
            break;
        default:
            assert false;
    }
}
Also used : SelfLoopPort(org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort)

Aggregations

SelfLoopPort (org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort)11 SelfHyperLoop (org.eclipse.elk.alg.layered.intermediate.loops.SelfHyperLoop)3 SelfLoopHolder (org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopHolder)3 PortSide (org.eclipse.elk.core.options.PortSide)3 ArrayList (java.util.ArrayList)2 LNode (org.eclipse.elk.alg.layered.graph.LNode)2 LPort (org.eclipse.elk.alg.layered.graph.LPort)2 SelfHyperLoopLabels (org.eclipse.elk.alg.layered.intermediate.loops.SelfHyperLoopLabels)2 KVector (org.eclipse.elk.core.math.KVector)2 List (java.util.List)1 Collectors (java.util.stream.Collectors)1 Stream (java.util.stream.Stream)1 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)1 LMargin (org.eclipse.elk.alg.layered.graph.LMargin)1 InternalProperties (org.eclipse.elk.alg.layered.options.InternalProperties)1 LayeredOptions (org.eclipse.elk.alg.layered.options.LayeredOptions)1