Search in sources :

Example 1 with LNode

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

the class HierarchicalPortOrthogonalEdgeRouter method correctSlantedEdgeSegments.

/**
 * Goes over the eastern and western hierarchical dummy nodes in the given layer and checks
 * whether their incident edges have slanted segments. Note that only the first and last
 * segment needs to be checked.
 *
 * @param layer the layer.
 */
private void correctSlantedEdgeSegments(final Layer layer) {
    for (LNode node : layer) {
        if (node.getType() != NodeType.EXTERNAL_PORT) {
            // We're only looking for hierarchical port dummies
            continue;
        }
        PortSide extPortSide = node.getProperty(InternalProperties.EXT_PORT_SIDE);
        if (extPortSide == PortSide.EAST || extPortSide == PortSide.WEST) {
            for (LEdge edge : node.getConnectedEdges()) {
                KVectorChain bendPoints = edge.getBendPoints();
                if (bendPoints.isEmpty()) {
                    // TODO: The edge has no bend points yet, but may still be slanted. Handle that!
                    continue;
                }
                // Correct a slanted segment connected to the source port if it belongs to our node
                LPort sourcePort = edge.getSource();
                if (sourcePort.getNode() == node) {
                    KVector firstBendPoint = bendPoints.getFirst();
                    firstBendPoint.y = sourcePort.getAbsoluteAnchor().y;
                }
                // Correct a slanted segment connected to the target port if it belongs to our node
                LPort targetPort = edge.getTarget();
                if (targetPort.getNode() == node) {
                    KVector lastBendPoint = bendPoints.getLast();
                    lastBendPoint.y = targetPort.getAbsoluteAnchor().y;
                }
            }
        }
    }
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) PortSide(org.eclipse.elk.core.options.PortSide) KVector(org.eclipse.elk.core.math.KVector)

Example 2 with LNode

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

the class HierarchicalPortOrthogonalEdgeRouter method routeEdges.

// /////////////////////////////////////////////////////////////////////////////
// STEP 3: EDGE ROUTING
/**
 * Routes nothern and southern hierarchical port edges and ajusts the graph's height and
 * offsets accordingly.
 *
 * @param monitor the progress monitor we're using.
 * @param layeredGraph the layered graph.
 * @param northSouthDummies the collection of restored northern and southern port dummies.
 */
private void routeEdges(final IElkProgressMonitor monitor, final LGraph layeredGraph, final Iterable<LNode> northSouthDummies) {
    // Prepare south and target layers for northern and southern routing
    Set<LNode> northernSourceLayer = Sets.newLinkedHashSet();
    Set<LNode> northernTargetLayer = Sets.newLinkedHashSet();
    Set<LNode> southernSourceLayer = Sets.newLinkedHashSet();
    Set<LNode> southernTargetLayer = Sets.newLinkedHashSet();
    // Find some routing parameters
    double nodeSpacing = layeredGraph.getProperty(LayeredOptions.SPACING_NODE_NODE).doubleValue();
    double edgeSpacing = layeredGraph.getProperty(LayeredOptions.SPACING_EDGE_EDGE).doubleValue();
    // connected to
    for (LNode hierarchicalPortDummy : northSouthDummies) {
        PortSide portSide = hierarchicalPortDummy.getProperty(InternalProperties.EXT_PORT_SIDE);
        if (portSide == PortSide.NORTH) {
            northernTargetLayer.add(hierarchicalPortDummy);
            for (LEdge edge : hierarchicalPortDummy.getIncomingEdges()) {
                northernSourceLayer.add(edge.getSource().getNode());
            }
        } else if (portSide == PortSide.SOUTH) {
            southernTargetLayer.add(hierarchicalPortDummy);
            for (LEdge edge : hierarchicalPortDummy.getIncomingEdges()) {
                southernSourceLayer.add(edge.getSource().getNode());
            }
        }
    }
    // Northern routing
    if (!northernSourceLayer.isEmpty()) {
        // Route the edges using a south-to-north orthogonal edge router
        OrthogonalRoutingGenerator routingGenerator = new OrthogonalRoutingGenerator(RoutingDirection.SOUTH_TO_NORTH, edgeSpacing, "extnorth");
        int slots = routingGenerator.routeEdges(monitor, layeredGraph, northernSourceLayer, 0, northernTargetLayer, -nodeSpacing - layeredGraph.getOffset().y);
        // If anything was routed, adjust the graph's offset and height
        if (slots > 0) {
            northernExtPortEdgeRoutingHeight = nodeSpacing + (slots - 1) * edgeSpacing;
            layeredGraph.getOffset().y += northernExtPortEdgeRoutingHeight;
            layeredGraph.getSize().y += northernExtPortEdgeRoutingHeight;
        }
    }
    // Southern routing
    if (!southernSourceLayer.isEmpty()) {
        // Route the edges using a north-to-south orthogonal edge router
        OrthogonalRoutingGenerator routingGenerator = new OrthogonalRoutingGenerator(RoutingDirection.NORTH_TO_SOUTH, edgeSpacing, "extsouth");
        int slots = routingGenerator.routeEdges(monitor, layeredGraph, southernSourceLayer, 0, southernTargetLayer, layeredGraph.getSize().y + nodeSpacing - layeredGraph.getOffset().y);
        // Adjust graph height.
        if (slots > 0) {
            layeredGraph.getSize().y += nodeSpacing + (slots - 1) * edgeSpacing;
        }
    }
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LNode(org.eclipse.elk.alg.layered.graph.LNode) PortSide(org.eclipse.elk.core.options.PortSide) OrthogonalRoutingGenerator(org.eclipse.elk.alg.layered.p5edges.orthogonal.OrthogonalRoutingGenerator) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint)

Example 3 with LNode

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

the class HierarchicalPortOrthogonalEdgeRouter method setNorthSouthDummyCoordinates.

// /////////////////////////////////////////////////////////////////////////////
// STEP 2: SET NORTH / SOUTH DUMMY COORDINATES
/**
 * Set coordinates for northern and southern external port dummy nodes.
 *
 * @param layeredGraph the layered graph.
 * @param northSouthDummies dummy nodes whose position to set.
 */
private void setNorthSouthDummyCoordinates(final LGraph layeredGraph, final List<LNode> northSouthDummies) {
    PortConstraints constraints = layeredGraph.getProperty(LayeredOptions.PORT_CONSTRAINTS);
    KVector graphSize = layeredGraph.getSize();
    LPadding graphPadding = layeredGraph.getPadding();
    double graphWidth = graphSize.x + graphPadding.left + graphPadding.right;
    double northY = 0 - graphPadding.top - layeredGraph.getOffset().y;
    double southY = graphSize.y + graphPadding.top + graphPadding.bottom - layeredGraph.getOffset().y;
    // Lists of northern and southern external port dummies
    List<LNode> northernDummies = Lists.newArrayList();
    List<LNode> southernDummies = Lists.newArrayList();
    for (LNode dummy : northSouthDummies) {
        // Set x coordinate
        switch(constraints) {
            case FREE:
            case FIXED_SIDE:
            case FIXED_ORDER:
                calculateNorthSouthDummyPositions(dummy);
                break;
            case FIXED_RATIO:
                applyNorthSouthDummyRatio(dummy, graphWidth);
                dummy.borderToContentAreaCoordinates(true, false);
                break;
            case FIXED_POS:
                applyNorthSouthDummyPosition(dummy);
                dummy.borderToContentAreaCoordinates(true, false);
                // Ensure that the graph is wide enough to hold the port
                graphSize.x = Math.max(graphSize.x, dummy.getPosition().x + dummy.getSize().x / 2.0);
                break;
        }
        // Set y coordinates and add the dummy to its respective list
        switch(dummy.getProperty(InternalProperties.EXT_PORT_SIDE)) {
            case NORTH:
                dummy.getPosition().y = northY;
                northernDummies.add((dummy));
                break;
            case SOUTH:
                dummy.getPosition().y = southY;
                southernDummies.add(dummy);
                break;
        }
    }
    // have been put on top of one another
    switch(constraints) {
        case FREE:
        case FIXED_SIDE:
            ensureUniquePositions(northernDummies, layeredGraph);
            ensureUniquePositions(southernDummies, layeredGraph);
            break;
        case FIXED_ORDER:
            restoreProperOrder(northernDummies, layeredGraph);
            restoreProperOrder(southernDummies, layeredGraph);
            break;
    }
}
Also used : LPadding(org.eclipse.elk.alg.layered.graph.LPadding) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) PortConstraints(org.eclipse.elk.core.options.PortConstraints)

Example 4 with LNode

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

the class HierarchicalPortOrthogonalEdgeRouter method fixCoordinates.

/**
 * Fixes the coordinates of the nodes in the given layer.
 *
 * @param layer the layer.
 * @param constraints external port constraints.
 * @param graph the graph.
 */
private void fixCoordinates(final Layer layer, final PortConstraints constraints, final LGraph graph) {
    // Get some geometric values from the graph
    LPadding padding = graph.getPadding();
    KVector offset = graph.getOffset();
    KVector graphActualSize = graph.getActualSize();
    double newActualGraphHeight = graphActualSize.y;
    // of the graph, so we're setting y coordinates of NORTH and SOUTH dummies in a second iteration
    for (LNode node : layer) {
        if (node.getType() != NodeType.EXTERNAL_PORT) {
            // We're only looking for hierarchical port dummies
            continue;
        }
        PortSide extPortSide = node.getProperty(InternalProperties.EXT_PORT_SIDE);
        KVector extPortSize = node.getProperty(InternalProperties.EXT_PORT_SIZE);
        KVector nodePosition = node.getPosition();
        // Set x coordinate
        switch(extPortSide) {
            case EAST:
                nodePosition.x = graph.getSize().x + padding.right - offset.x;
                break;
            case WEST:
                nodePosition.x = -offset.x - padding.left;
                break;
        }
        // Set y coordinate
        double requiredActualGraphHeight = 0.0;
        switch(extPortSide) {
            case EAST:
            case WEST:
                if (constraints == PortConstraints.FIXED_RATIO) {
                    double ratio = node.getProperty(InternalProperties.PORT_RATIO_OR_POSITION);
                    nodePosition.y = graphActualSize.y * ratio - node.getProperty(LayeredOptions.PORT_ANCHOR).y;
                    requiredActualGraphHeight = nodePosition.y + extPortSize.y;
                    node.borderToContentAreaCoordinates(false, true);
                } else if (constraints == PortConstraints.FIXED_POS) {
                    nodePosition.y = node.getProperty(InternalProperties.PORT_RATIO_OR_POSITION) - node.getProperty(LayeredOptions.PORT_ANCHOR).y;
                    requiredActualGraphHeight = nodePosition.y + extPortSize.y;
                    node.borderToContentAreaCoordinates(false, true);
                }
                break;
        }
        newActualGraphHeight = Math.max(newActualGraphHeight, requiredActualGraphHeight);
    }
    // Make the graph larger, if necessary
    graph.getSize().y += newActualGraphHeight - graphActualSize.y;
    // Iterate over NORTH and SOUTH dummies now that the graph's height is fixed
    for (LNode node : layer) {
        if (node.getType() != NodeType.EXTERNAL_PORT) {
            // We're only looking for hierarchical port dummies
            continue;
        }
        PortSide extPortSide = node.getProperty(InternalProperties.EXT_PORT_SIDE);
        KVector nodePosition = node.getPosition();
        // Set y coordinate
        switch(extPortSide) {
            case NORTH:
                nodePosition.y = -offset.y - padding.top;
                break;
            case SOUTH:
                nodePosition.y = graph.getSize().y + padding.bottom - offset.y;
                break;
        }
    }
}
Also used : LPadding(org.eclipse.elk.alg.layered.graph.LPadding) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) PortSide(org.eclipse.elk.core.options.PortSide)

Example 5 with LNode

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

the class HierarchicalPortOrthogonalEdgeRouter method removeTemporaryNorthSouthDummies.

// /////////////////////////////////////////////////////////////////////////////
// STEP 4: REMOVE TEMPORARY DUMMIES
/**
 * Removes the temporary hierarchical port dummies, reconnecting their incoming and outgoing
 * edges to the original dummies and setting the appropriate bend points.
 *
 * @param layeredGraph the layered graph.
 */
private void removeTemporaryNorthSouthDummies(final LGraph layeredGraph) {
    List<LNode> nodesToRemove = Lists.newArrayList();
    // Iterate through all layers
    for (Layer layer : layeredGraph) {
        for (LNode node : layer) {
            if (node.getType() != NodeType.EXTERNAL_PORT) {
                // We're only looking for hierarchical port dummies
                continue;
            }
            if (!node.hasProperty(InternalProperties.EXT_PORT_REPLACED_DUMMY)) {
                // We're only looking for temporary north / south dummies
                continue;
            }
            // There must be a port where all edges come in, another port where edges go out, and
            // a port with an edge connecting node and origin (that one was added previously by
            // this processor)
            LPort nodeInPort = null;
            LPort nodeOutPort = null;
            LPort nodeOriginPort = null;
            for (LPort port : node.getPorts()) {
                switch(port.getSide()) {
                    case WEST:
                        nodeInPort = port;
                        break;
                    case EAST:
                        nodeOutPort = port;
                        break;
                    default:
                        nodeOriginPort = port;
                }
            }
            // Find the edge connecting this dummy to the original external port dummy that we
            // restored just a while ago
            LEdge nodeToOriginEdge = nodeOriginPort.getOutgoingEdges().get(0);
            // Compute bend points for incoming edges
            KVectorChain incomingEdgeBendPoints = new KVectorChain(nodeToOriginEdge.getBendPoints());
            KVector firstBendPoint = new KVector(nodeOriginPort.getPosition());
            firstBendPoint.add(node.getPosition());
            incomingEdgeBendPoints.add(0, firstBendPoint);
            // Compute bend points for outgoing edges
            KVectorChain outgoingEdgeBendPoints = KVectorChain.reverse(nodeToOriginEdge.getBendPoints());
            KVector lastBendPoint = new KVector(nodeOriginPort.getPosition());
            lastBendPoint.add(node.getPosition());
            outgoingEdgeBendPoints.add(lastBendPoint);
            // Retrieve the original hierarchical port dummy
            LNode replacedDummy = (LNode) node.getProperty(InternalProperties.EXT_PORT_REPLACED_DUMMY);
            LPort replacedDummyPort = replacedDummy.getPorts().get(0);
            // Reroute all the input port's edges
            LEdge[] edges = nodeInPort.getIncomingEdges().toArray(new LEdge[0]);
            for (LEdge edge : edges) {
                edge.setTarget(replacedDummyPort);
                edge.getBendPoints().addAllAsCopies(edge.getBendPoints().size(), incomingEdgeBendPoints);
            }
            // Reroute all the output port's edges
            edges = LGraphUtil.toEdgeArray(nodeOutPort.getOutgoingEdges());
            for (LEdge edge : edges) {
                edge.setSource(replacedDummyPort);
                edge.getBendPoints().addAllAsCopies(0, outgoingEdgeBendPoints);
            }
            // Remove connection between node and original hierarchical port dummy
            nodeToOriginEdge.setSource(null);
            nodeToOriginEdge.setTarget(null);
            // Remember the temporary node for removal
            nodesToRemove.add(node);
        }
    }
    // Remove nodes
    for (LNode node : nodesToRemove) {
        node.setLayer(null);
    }
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) Layer(org.eclipse.elk.alg.layered.graph.Layer)

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