Search in sources :

Example 11 with PortConstraints

use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.

the class HierarchicalPortPositionProcessor method fixCoordinates.

/**
 * Fixes the y coordinates of external port dummies in the given layer.
 *
 * @param layer the layer.
 * @param layeredGraph the layered graph.
 * @param portConstraints the port constraints that apply to external ports.
 * @param graphHeight height of the graph.
 */
private void fixCoordinates(final Layer layer, final LGraph layeredGraph) {
    PortConstraints portConstraints = layeredGraph.getProperty(LayeredOptions.PORT_CONSTRAINTS);
    if (!(portConstraints.isRatioFixed() || portConstraints.isPosFixed())) {
        // If coordinates are free to be set, we're done
        return;
    }
    double graphHeight = layeredGraph.getActualSize().y;
    // Iterate over the layer's nodes
    for (LNode node : layer) {
        // We only care about external port dummies...
        if (node.getType() != NodeType.EXTERNAL_PORT) {
            continue;
        }
        // ...representing eastern or western ports.
        PortSide extPortSide = node.getProperty(InternalProperties.EXT_PORT_SIDE);
        if (extPortSide != PortSide.EAST && extPortSide != PortSide.WEST) {
            continue;
        }
        double finalYCoordinate = node.getProperty(InternalProperties.PORT_RATIO_OR_POSITION);
        if (portConstraints == PortConstraints.FIXED_RATIO) {
            // finalYCoordinate is a ratio that must be multiplied with the graph's height
            finalYCoordinate *= graphHeight;
        }
        // Apply the node's new Y coordinate
        node.getPosition().y = finalYCoordinate - node.getProperty(LayeredOptions.PORT_ANCHOR).y;
        node.borderToContentAreaCoordinates(false, true);
    }
}
Also used : LNode(org.eclipse.elk.alg.layered.graph.LNode) PortSide(org.eclipse.elk.core.options.PortSide) PortConstraints(org.eclipse.elk.core.options.PortConstraints)

Example 12 with PortConstraints

use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.

the class HierarchicalPortConstraintProcessor method processNorthernAndSouthernPortDummies.

// /////////////////////////////////////////////////////////////////////////////
// North / South Hierarchical Port Dummies
/**
 * Process northern and southern hierarchical port dummies.
 *
 * @param layeredGraph the layered graph.
 */
private void processNorthernAndSouthernPortDummies(final LGraph layeredGraph) {
    // If the port constraints are not at least FIXED_SIDE, there's nothing to do here
    PortConstraints portConstraints = layeredGraph.getProperty(LayeredOptions.PORT_CONSTRAINTS);
    if (!portConstraints.isSideFixed()) {
        return;
    }
    List<Layer> layers = layeredGraph.getLayers();
    int layerCount = layers.size();
    // For each layer, we keep a map of dummy nodes created for a given original external port
    // dummy. This lets us remember which new dummy node was created for which original external
    // port dummy in which layer. We also keep a list of dummy nodes to be added to each layer
    // since iterating over the new dummy nodes in the map may mess up their order since we don't
    // have hashCode() implemented. Once we do, this code can be reworked to just use the maps
    // again.
    // We keep enough space to hold layerCount + 2 instances of each data structure because we
    // might have to add a new first and last layer, even though that shouldn't normally happen
    List<Map<Object, LNode>> extPortToDummyNodeMap = Lists.newArrayListWithExpectedSize(layerCount + 2);
    List<List<LNode>> newDummyNodes = Lists.newArrayListWithExpectedSize(layerCount + 2);
    // Add maps and lists for a new first layer that might have to be created as well as for the
    // current first layer. A map for the next layer is added on each iteration of the for loop
    extPortToDummyNodeMap.add(new HashMap<Object, LNode>());
    extPortToDummyNodeMap.add(new HashMap<Object, LNode>());
    newDummyNodes.add(new ArrayList<LNode>());
    newDummyNodes.add(new ArrayList<LNode>());
    // We remember each original external port dummy we encounter (they must be removed from the layers later)
    List<LNode> originalExternalPortDummies = Lists.newArrayList();
    // Iterate through each layer
    for (int currLayerIdx = 0; currLayerIdx < layerCount; currLayerIdx++) {
        Layer currentLayer = layers.get(currLayerIdx);
        // Dummy node maps and lists for the next and previous layer
        Map<Object, LNode> prevExtPortToDummyNodesMap = extPortToDummyNodeMap.get(currLayerIdx);
        Map<Object, LNode> nextExtPortToDummyNodesMap = Maps.newHashMap();
        extPortToDummyNodeMap.add(nextExtPortToDummyNodesMap);
        List<LNode> prevNewDummyNodes = newDummyNodes.get(currLayerIdx);
        List<LNode> nextNewDummyNodes = Lists.newArrayList();
        newDummyNodes.add(nextNewDummyNodes);
        // northern / southern hierarchical port dummies
        for (LNode currentNode : currentLayer) {
            if (isNorthernOrSouthernDummy(currentNode)) {
                // It's a northern or southern external port dummy. Schedule for removal and move on to next node
                originalExternalPortDummies.add(currentNode);
                continue;
            }
            // Iterate over the node's incoming edges
            for (LEdge edge : currentNode.getIncomingEdges()) {
                LNode sourceNode = edge.getSource().getNode();
                // Check if it's a northern / southern dummy node
                if (!isNorthernOrSouthernDummy(sourceNode)) {
                    continue;
                }
                // See if a dummy has already been created for the previous layer
                LNode prevLayerDummy = prevExtPortToDummyNodesMap.get(sourceNode.getProperty(InternalProperties.ORIGIN));
                if (prevLayerDummy == null) {
                    // No. Create one.
                    prevLayerDummy = createDummy(layeredGraph, sourceNode);
                    prevExtPortToDummyNodesMap.put(sourceNode.getProperty(InternalProperties.ORIGIN), prevLayerDummy);
                    prevNewDummyNodes.add(prevLayerDummy);
                }
                // Reroute the edge
                edge.setSource(prevLayerDummy.getPorts().get(DUMMY_OUTPUT_PORT));
            }
            // Iterate over the node's outgoing edges
            for (LEdge edge : currentNode.getOutgoingEdges()) {
                LNode targetNode = edge.getTarget().getNode();
                // Check if it's a northern / southern dummy node
                if (!isNorthernOrSouthernDummy(targetNode)) {
                    continue;
                }
                // See if a dummy has already been created for the next layer
                LNode nextLayerDummy = nextExtPortToDummyNodesMap.get(targetNode.getProperty(InternalProperties.ORIGIN));
                if (nextLayerDummy == null) {
                    // No. Create one.
                    nextLayerDummy = createDummy(layeredGraph, targetNode);
                    nextExtPortToDummyNodesMap.put(targetNode.getProperty(InternalProperties.ORIGIN), nextLayerDummy);
                    nextNewDummyNodes.add(nextLayerDummy);
                }
                // Reroute the edge
                edge.setTarget(nextLayerDummy.getPorts().get(DUMMY_INPUT_PORT));
            }
        }
    }
    // Add the newly created dummy nodes
    for (int i = 0; i < newDummyNodes.size(); i++) {
        List<LNode> nodeList = newDummyNodes.get(i);
        if (nodeList.isEmpty()) {
            // No dummy nodes, so just move on
            continue;
        }
        // Find the layer the dummy nodes should be added to
        Layer layer = null;
        if (i == 0) {
            // A new first layer must be created
            layer = new Layer(layeredGraph);
            layers.add(0, layer);
        } else if (i == extPortToDummyNodeMap.size() - 1) {
            // A new layer layer must be created
            layer = new Layer(layeredGraph);
            layers.add(layer);
        } else {
            layer = layers.get(i - 1);
        }
        for (LNode dummy : nodeList) {
            dummy.setLayer(layer);
        }
    }
    // Iterate through the hierarchical port dummies and remove them
    for (LNode originalDummy : originalExternalPortDummies) {
        // Remove the original dummy; new dummy nodes have already been created for it
        originalDummy.setLayer(null);
    }
    // Remember the original external port dummies in the graph
    layeredGraph.setProperty(InternalProperties.EXT_PORT_REPLACED_DUMMIES, originalExternalPortDummies);
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) PortConstraints(org.eclipse.elk.core.options.PortConstraints) Layer(org.eclipse.elk.alg.layered.graph.Layer) ArrayList(java.util.ArrayList) List(java.util.List) LNode(org.eclipse.elk.alg.layered.graph.LNode) HashMap(java.util.HashMap) Map(java.util.Map)

Example 13 with PortConstraints

use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.

the class CompoundGraphPreprocessor method transformHierarchyEdges.

/**
 * Recursively transform cross-hierarchy edges into sequences of dummy ports and dummy edges.
 *
 * @param graph
 *            the layered graph to process
 * @param parentNode
 *            the node that represents the graph in the upper hierarchy level, or {@code null}
 *            if it already is on top-level
 * @return the external ports created to split edges that cross the boundary of the parent node
 */
private List<ExternalPort> transformHierarchyEdges(final LGraph graph, final LNode parentNode) {
    // process all children and recurse down to gather their external ports
    List<ExternalPort> containedExternalPorts = Lists.newArrayList();
    for (LNode node : graph.getLayerlessNodes()) {
        LGraph nestedGraph = node.getNestedGraph();
        if (nestedGraph != null) {
            // recursively process the child graph
            List<ExternalPort> childPorts = transformHierarchyEdges(nestedGraph, node);
            containedExternalPorts.addAll(childPorts);
            // process inside self loops
            processInsideSelfLoops(nestedGraph, node);
            // will already have been created, but perhaps not all)
            if (nestedGraph.getProperty(InternalProperties.GRAPH_PROPERTIES).contains(GraphProperties.EXTERNAL_PORTS)) {
                // We need the port constraints to position external ports (Issues KIPRA-1528, ELK-48)
                PortConstraints portConstraints = node.getProperty(LayeredOptions.PORT_CONSTRAINTS);
                boolean insidePortLabels = node.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT).contains(PortLabelPlacement.INSIDE);
                for (LPort port : node.getPorts()) {
                    // Make sure that every port has a dummy node created for it
                    LNode dummyNode = dummyNodeMap.get(port);
                    if (dummyNode == null) {
                        dummyNode = LGraphUtil.createExternalPortDummy(port, portConstraints, port.getSide(), -port.getNetFlow(), null, new KVector(), port.getSize(), nestedGraph.getProperty(LayeredOptions.DIRECTION), nestedGraph);
                        dummyNode.setProperty(InternalProperties.ORIGIN, port);
                        dummyNodeMap.put(port, dummyNode);
                        nestedGraph.getLayerlessNodes().add(dummyNode);
                    }
                    // We need to reserve space for external port labels by adding those labels to our dummy nodes
                    LPort dummyNodePort = dummyNode.getPorts().get(0);
                    for (LLabel extPortLabel : port.getLabels()) {
                        LLabel dummyPortLabel = new LLabel();
                        dummyPortLabel.getSize().x = extPortLabel.getSize().x;
                        dummyPortLabel.getSize().y = extPortLabel.getSize().y;
                        dummyNodePort.getLabels().add(dummyPortLabel);
                        // But if the port labels are fixed, we should consider the part that is inside the node.
                        if (!insidePortLabels) {
                            PortSide side = port.getSide();
                            double insidePart = 0;
                            if (PortLabelPlacement.isFixed(node.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT))) {
                                // We use 0 as port border offset here, as we only want the label part that is
                                // inside the node "after" the port.
                                insidePart = ElkUtil.computeInsidePart(extPortLabel.getPosition(), extPortLabel.getSize(), port.getSize(), 0, side);
                            }
                            if (portConstraints == PortConstraints.FREE || PortSide.SIDES_EAST_WEST.contains(side)) {
                                dummyPortLabel.getSize().x = insidePart;
                            } else {
                                dummyPortLabel.getSize().y = insidePart;
                            }
                        }
                    }
                }
            }
        }
    }
    // this will be the list of external ports we will export
    List<ExternalPort> exportedExternalPorts = Lists.newArrayList();
    // process the cross-hierarchy edges connected to the inside of the child nodes
    processInnerHierarchicalEdgeSegments(graph, parentNode, containedExternalPorts, exportedExternalPorts);
    // process the cross-hierarchy edges connected to the outside of the parent node
    if (parentNode != null) {
        processOuterHierarchicalEdgeSegments(graph, parentNode, exportedExternalPorts);
    }
    return exportedExternalPorts;
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) KVector(org.eclipse.elk.core.math.KVector) PortSide(org.eclipse.elk.core.options.PortSide) PortConstraints(org.eclipse.elk.core.options.PortConstraints)

Example 14 with PortConstraints

use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.

the class LGraphUtil method computeGraphProperties.

// /////////////////////////////////////////////////////////////////////////////
// Graph Properties
/**
 * Compute the graph properties of the given layered graph. These properties are important
 * to determine which intermediate processors are included in the layout run.
 * Ideally the properties are computed during the import of the source format into {@link LGraph},
 * e.g. as done in {@code KGraphImporter}. This method is offered only for convenience.
 * <p>
 * The nodes are expected to be in the {@link LGraph#getLayerlessNodes()} list.
 * </p>
 *
 * @param layeredGraph a layered graph
 */
public static void computeGraphProperties(final LGraph layeredGraph) {
    Set<GraphProperties> props = layeredGraph.getProperty(InternalProperties.GRAPH_PROPERTIES);
    if (!props.isEmpty()) {
        props.clear();
    }
    Direction direction = getDirection(layeredGraph);
    for (LNode node : layeredGraph.getLayerlessNodes()) {
        if (node.getProperty(LayeredOptions.COMMENT_BOX)) {
            props.add(GraphProperties.COMMENTS);
        } else if (node.getProperty(LayeredOptions.HYPERNODE)) {
            props.add(GraphProperties.HYPERNODES);
            props.add(GraphProperties.HYPEREDGES);
        } else if (node.getType() == NodeType.EXTERNAL_PORT) {
            props.add(GraphProperties.EXTERNAL_PORTS);
        }
        PortConstraints portConstraints = node.getProperty(LayeredOptions.PORT_CONSTRAINTS);
        if (portConstraints == PortConstraints.UNDEFINED) {
            // correct the port constraints value
            node.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FREE);
        } else if (portConstraints != PortConstraints.FREE) {
            props.add(GraphProperties.NON_FREE_PORTS);
        }
        for (LPort port : node.getPorts()) {
            if (port.getIncomingEdges().size() + port.getOutgoingEdges().size() > 1) {
                props.add(GraphProperties.HYPEREDGES);
            }
            PortSide portSide = port.getSide();
            switch(direction) {
                case UP:
                case DOWN:
                    if (portSide == PortSide.EAST || portSide == PortSide.WEST) {
                        props.add(GraphProperties.NORTH_SOUTH_PORTS);
                    }
                    break;
                default:
                    if (portSide == PortSide.NORTH || portSide == PortSide.SOUTH) {
                        props.add(GraphProperties.NORTH_SOUTH_PORTS);
                    }
            }
            for (LEdge edge : port.getOutgoingEdges()) {
                if (edge.getTarget().getNode() == node) {
                    props.add(GraphProperties.SELF_LOOPS);
                }
                for (LLabel label : edge.getLabels()) {
                    switch(label.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT)) {
                        case CENTER:
                            props.add(GraphProperties.CENTER_LABELS);
                            break;
                        case HEAD:
                        case TAIL:
                            props.add(GraphProperties.END_LABELS);
                            break;
                    }
                }
            }
        }
    }
}
Also used : GraphProperties(org.eclipse.elk.alg.layered.options.GraphProperties) PortSide(org.eclipse.elk.core.options.PortSide) Direction(org.eclipse.elk.core.options.Direction) PortConstraints(org.eclipse.elk.core.options.PortConstraints)

Example 15 with PortConstraints

use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.

the class GraphConfigurator method copyPortConstraints.

private void copyPortConstraints(final LNode node) {
    PortConstraints originalPortconstraints = node.getProperty(LayeredOptions.PORT_CONSTRAINTS);
    node.setProperty(InternalProperties.ORIGINAL_PORT_CONSTRAINTS, originalPortconstraints);
    LGraph nestedGraph = node.getNestedGraph();
    if (nestedGraph != null) {
        copyPortContraints(nestedGraph);
    }
}
Also used : LGraph(org.eclipse.elk.alg.layered.graph.LGraph) PortConstraints(org.eclipse.elk.core.options.PortConstraints)

Aggregations

PortConstraints (org.eclipse.elk.core.options.PortConstraints)18 LNode (org.eclipse.elk.alg.layered.graph.LNode)9 PortSide (org.eclipse.elk.core.options.PortSide)8 Direction (org.eclipse.elk.core.options.Direction)6 LPort (org.eclipse.elk.alg.layered.graph.LPort)5 KVector (org.eclipse.elk.core.math.KVector)5 SizeConstraint (org.eclipse.elk.core.options.SizeConstraint)5 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)4 ElkLabel (org.eclipse.elk.graph.ElkLabel)4 ElkNode (org.eclipse.elk.graph.ElkNode)4 ElkPort (org.eclipse.elk.graph.ElkPort)4 EnumSet (java.util.EnumSet)3 List (java.util.List)3 Map (java.util.Map)3 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)3 Layer (org.eclipse.elk.alg.layered.graph.Layer)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 Set (java.util.Set)2 LPadding (org.eclipse.elk.alg.layered.graph.LPadding)2