Search in sources :

Example 21 with ElkEdge

use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.

the class ElkGraphImporter method checkExternalPorts.

// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// External Port Transformation
/**
 * Checks if external ports processing should be active. This is the case if the parent node has
 * ports and at least one of the following conditions is true:
 * <ul>
 *   <li>
 *     Port label placement is set to {@code INSIDE} and at least one of the ports has a label.
 *   </li>
 *   <li>
 *     At least one of the ports has an edge that connects to the insides of the parent node.
 *   </li>
 *   <li>
 *     There is a self-loop that should be routed inside the node.
 *   </li>
 * </ul>
 *
 * @param elkgraph
 *            a KGraph we want to check for external ports.
 * @param graphProperties
 *            the set of graph properties to store our results in.
 */
private void checkExternalPorts(final ElkNode elkgraph, final Set<GraphProperties> graphProperties) {
    final boolean enableSelfLoops = elkgraph.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_ACTIVATE);
    final Set<PortLabelPlacement> portLabelPlacement = elkgraph.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT);
    // We're iterating over the ports until we've determined that we have both external ports and
    // hyperedges, or if there are no more ports left
    boolean hasExternalPorts = false;
    boolean hasHyperedges = false;
    final Iterator<ElkPort> portIterator = elkgraph.getPorts().iterator();
    while (portIterator.hasNext() && (!hasExternalPorts || !hasHyperedges)) {
        final ElkPort elkport = portIterator.next();
        // Find out if there are edges connected to external ports of the graph (this is the case
        // for inside self loops as well as for edges connected to children)
        int externalPortEdges = 0;
        for (ElkEdge elkedge : ElkGraphUtil.allIncidentEdges(elkport)) {
            boolean isInsideSelfLoop = enableSelfLoops && elkedge.isSelfloop() && elkedge.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_YO);
            boolean connectsToChild = elkedge.getSources().contains(elkport) ? elkgraph == ElkGraphUtil.connectableShapeToNode(elkedge.getTargets().get(0)).getParent() : elkgraph == ElkGraphUtil.connectableShapeToNode(elkedge.getSources().get(0)).getParent();
            if (isInsideSelfLoop || connectsToChild) {
                externalPortEdges++;
                if (externalPortEdges > 1) {
                    break;
                }
            }
        }
        // External ports?
        if (externalPortEdges > 0) {
            hasExternalPorts = true;
        } else if (portLabelPlacement.contains(PortLabelPlacement.INSIDE) && elkport.getLabels().size() > 0) {
            hasExternalPorts = true;
        }
        // Hyperedges, even?
        if (externalPortEdges > 1) {
            hasHyperedges = true;
        }
    }
    // Update graph properties
    if (hasExternalPorts) {
        graphProperties.add(GraphProperties.EXTERNAL_PORTS);
    }
    if (hasHyperedges) {
        graphProperties.add(GraphProperties.HYPEREDGES);
    }
}
Also used : PortLabelPlacement(org.eclipse.elk.core.options.PortLabelPlacement) ElkPort(org.eclipse.elk.graph.ElkPort) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 22 with ElkEdge

use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.

the class ElkGraphImporter method importHierarchicalGraph.

/**
 * Imports the graph hierarchy rooted at the given graph.
 *
 * @param elkgraph
 *            graph to import.
 * @param lgraph
 *            graph to add the direct children of the current hierarchy level to.
 */
private void importHierarchicalGraph(final ElkNode elkgraph, final LGraph lgraph) {
    final Queue<ElkNode> elkGraphQueue = Lists.newLinkedList();
    Direction parentGraphDirection = lgraph.getProperty(LayeredOptions.DIRECTION);
    // Model order index for nodes
    int index = 0;
    // Transform the node's children
    elkGraphQueue.addAll(elkgraph.getChildren());
    while (!elkGraphQueue.isEmpty()) {
        ElkNode elknode = elkGraphQueue.poll();
        if (elkgraph.getProperty(LayeredOptions.CONSIDER_MODEL_ORDER_STRATEGY) != OrderingStrategy.NONE || elkgraph.getProperty(LayeredOptions.CYCLE_BREAKING_STRATEGY) == CycleBreakingStrategy.MODEL_ORDER) {
            // Assign a model order to the nodes as they are read
            elknode.setProperty(InternalProperties.MODEL_ORDER, index++);
        }
        // Check if the current node is to be laid out in the first place
        boolean isNodeToBeLaidOut = !elknode.getProperty(LayeredOptions.NO_LAYOUT);
        if (isNodeToBeLaidOut) {
            // Check if there has to be an LGraph for this node (which is the case if it has children or inside
            // self-loops, and if it does not have another layout algorithm configured)
            boolean hasChildren = !elknode.getChildren().isEmpty();
            boolean hasInsideSelfLoops = hasInsideSelfLoops(elknode);
            boolean hasHierarchyHandlingEnabled = elknode.getProperty(LayeredOptions.HIERARCHY_HANDLING) == HierarchyHandling.INCLUDE_CHILDREN;
            boolean usesElkLayered = !elknode.hasProperty(CoreOptions.ALGORITHM) || elknode.getProperty(CoreOptions.ALGORITHM).equals(LayeredOptions.ALGORITHM_ID);
            LGraph nestedGraph = null;
            if (usesElkLayered && hasHierarchyHandlingEnabled && (hasChildren || hasInsideSelfLoops)) {
                nestedGraph = createLGraph(elknode);
                nestedGraph.setProperty(LayeredOptions.DIRECTION, parentGraphDirection);
                // Apply a spacing configuration, for details see comment int #importGraph(...)
                if (nestedGraph.hasProperty(LayeredOptions.SPACING_BASE_VALUE)) {
                    LayeredSpacings.withBaseValue(nestedGraph.getProperty(LayeredOptions.SPACING_BASE_VALUE)).apply(nestedGraph);
                }
                // if the size constraints are not empty
                if (shouldCalculateMinimumGraphSize(elknode)) {
                    final LGraph finalNestedGraph = nestedGraph;
                    elknode.getPorts().stream().forEach(elkport -> ensureDefinedPortSide(finalNestedGraph, elkport));
                    calculateMinimumGraphSize(elknode, nestedGraph);
                }
            }
            // Transform da node!!!
            LGraph parentLGraph = lgraph;
            LNode parentLNode = (LNode) nodeAndPortMap.get(elknode.getParent());
            if (parentLNode != null) {
                parentLGraph = parentLNode.getNestedGraph();
            }
            LNode lnode = transformNode(elknode, parentLGraph);
            // Setup hierarchical relationships
            if (nestedGraph != null) {
                lnode.setNestedGraph(nestedGraph);
                nestedGraph.setParentNode(lnode);
                elkGraphQueue.addAll(elknode.getChildren());
            }
        }
    }
    // Model order index for edges.
    index = 0;
    // Transform the edges
    elkGraphQueue.add(elkgraph);
    while (!elkGraphQueue.isEmpty()) {
        ElkNode elkGraphNode = elkGraphQueue.poll();
        for (ElkEdge elkedge : elkGraphNode.getContainedEdges()) {
            // We don't support hyperedges
            checkEdgeValidity(elkedge);
            if (elkgraph.getProperty(LayeredOptions.CONSIDER_MODEL_ORDER_STRATEGY) != OrderingStrategy.NONE || elkgraph.getProperty(LayeredOptions.CYCLE_BREAKING_STRATEGY) == CycleBreakingStrategy.MODEL_ORDER) {
                // Assign a model order to the edges as they are read
                elkedge.setProperty(InternalProperties.MODEL_ORDER, index++);
            }
            ElkNode sourceNode = ElkGraphUtil.connectableShapeToNode(elkedge.getSources().get(0));
            ElkNode targetNode = ElkGraphUtil.connectableShapeToNode(elkedge.getTargets().get(0));
            // Don't bother if either the edge or at least one of its end points are excluded from layout
            if (elkedge.getProperty(LayeredOptions.NO_LAYOUT) || sourceNode.getProperty(LayeredOptions.NO_LAYOUT) || targetNode.getProperty(LayeredOptions.NO_LAYOUT)) {
                continue;
            }
            // Check if this edge is an inside self-loop
            boolean isInsideSelfLoop = elkedge.isSelfloop() && sourceNode.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_ACTIVATE) && elkedge.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_YO);
            // Find the graph the edge will be placed in. Basically, if the edge is an inside
            // self loop or connects one of its end points to a descendant, the edge will be
            // placed in the graph that represents that end point's insides. Otherwise, it will
            // be placed in the current graph.
            ElkNode parentElkGraph = elkGraphNode;
            if (isInsideSelfLoop || ElkGraphUtil.isDescendant(targetNode, sourceNode)) {
                parentElkGraph = sourceNode;
            } else if (ElkGraphUtil.isDescendant(sourceNode, targetNode)) {
                parentElkGraph = targetNode;
            }
            LGraph parentLGraph = lgraph;
            LNode parentLNode = (LNode) nodeAndPortMap.get(parentElkGraph);
            if (parentLNode != null) {
                parentLGraph = parentLNode.getNestedGraph();
            }
            // Transform the edge, finally...
            LEdge ledge = transformEdge(elkedge, parentElkGraph, parentLGraph);
            // Find the graph the edge's coordinates will have to be made relative to during export. This will only
            // do something if the edge containment inside ELK Layered differs from the edge containment in the
            // ELK graph
            ledge.setProperty(InternalProperties.COORDINATE_SYSTEM_ORIGIN, findCoordinateSystemOrigin(elkedge, elkgraph, lgraph));
        }
        // We may need to look at edges contained in the current graph node's children as well.
        // this is true unless either the current graph node does not have hierarchy handling
        // enabled, or a child has another layout algorithm configured
        boolean hasHierarchyHandlingEnabled = elkGraphNode.getProperty(LayeredOptions.HIERARCHY_HANDLING) == HierarchyHandling.INCLUDE_CHILDREN;
        if (hasHierarchyHandlingEnabled) {
            for (ElkNode elkChildGraphNode : elkGraphNode.getChildren()) {
                boolean usesElkLayered = !elkChildGraphNode.hasProperty(CoreOptions.ALGORITHM) || elkChildGraphNode.getProperty(CoreOptions.ALGORITHM).equals(LayeredOptions.ALGORITHM_ID);
                boolean partOfSameLayoutRun = elkChildGraphNode.getProperty(LayeredOptions.HIERARCHY_HANDLING) == HierarchyHandling.INCLUDE_CHILDREN;
                if (usesElkLayered && partOfSameLayoutRun) {
                    elkGraphQueue.add(elkChildGraphNode);
                }
            }
        }
    }
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LNode(org.eclipse.elk.alg.layered.graph.LNode) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) Direction(org.eclipse.elk.core.options.Direction) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 23 with ElkEdge

use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.

the class ElkGraphImporter method applyLayout.

// /////////////////////////////////////////////////////////////////////////////
// Apply Layout Results
@Override
public void applyLayout(final TGraph tGraph) {
    // get the corresponding kGraph
    ElkNode elkgraph = (ElkNode) tGraph.getProperty(InternalProperties.ORIGIN);
    // calculate the offset from border spacing and node distribution
    double minXPos = Integer.MAX_VALUE;
    double minYPos = Integer.MAX_VALUE;
    double maxXPos = Integer.MIN_VALUE;
    double maxYPos = Integer.MIN_VALUE;
    for (TNode tNode : tGraph.getNodes()) {
        KVector pos = tNode.getPosition();
        KVector size = tNode.getSize();
        minXPos = Math.min(minXPos, pos.x - size.x / 2);
        minYPos = Math.min(minYPos, pos.y - size.y / 2);
        maxXPos = Math.max(maxXPos, pos.x + size.x / 2);
        maxYPos = Math.max(maxYPos, pos.y + size.y / 2);
    }
    ElkPadding padding = elkgraph.getProperty(MrTreeOptions.PADDING);
    KVector offset = new KVector(padding.getLeft() - minXPos, padding.getTop() - minYPos);
    // process the nodes
    for (TNode tNode : tGraph.getNodes()) {
        Object object = tNode.getProperty(InternalProperties.ORIGIN);
        if (object instanceof ElkNode) {
            // set the node position
            ElkNode elknode = (ElkNode) object;
            KVector nodePos = tNode.getPosition().add(offset);
            elknode.setLocation(nodePos.x - elknode.getWidth() / 2, nodePos.y - elknode.getHeight() / 2);
        }
    }
    // process the edges
    for (TEdge tEdge : tGraph.getEdges()) {
        ElkEdge elkedge = (ElkEdge) tEdge.getProperty(InternalProperties.ORIGIN);
        if (elkedge != null) {
            KVectorChain bendPoints = tEdge.getBendPoints();
            // add the source port and target points to the vector chain
            KVector sourcePoint = new KVector(tEdge.getSource().getPosition());
            bendPoints.addFirst(sourcePoint);
            KVector targetPoint = new KVector(tEdge.getTarget().getPosition());
            bendPoints.addLast(targetPoint);
            // correct the source and target points
            toNodeBorder(sourcePoint, bendPoints.get(1), tEdge.getSource().getSize());
            toNodeBorder(targetPoint, bendPoints.get(bendPoints.size() - 2), tEdge.getTarget().getSize());
            ElkEdgeSection edgeSection = ElkGraphUtil.firstEdgeSection(elkedge, true, true);
            ElkUtil.applyVectorChain(bendPoints, edgeSection);
        }
    }
    // set up the graph
    double width = maxXPos - minXPos + padding.getHorizontal();
    double height = maxYPos - minYPos + padding.getVertical();
    ElkUtil.resizeNode(elkgraph, width, height, false, false);
}
Also used : TEdge(org.eclipse.elk.alg.mrtree.graph.TEdge) TNode(org.eclipse.elk.alg.mrtree.graph.TNode) ElkNode(org.eclipse.elk.graph.ElkNode) KVectorChain(org.eclipse.elk.core.math.KVectorChain) KVector(org.eclipse.elk.core.math.KVector) ElkPadding(org.eclipse.elk.core.math.ElkPadding) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 24 with ElkEdge

use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.

the class ElkUtil method printElementPath.

// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DEBUGGING
/**
 * Print information on the given graph element to the given string builder.
 */
public static void printElementPath(final ElkGraphElement element, final StringBuilder builder) {
    // Print the containing element
    if (element.eContainer() instanceof ElkGraphElement) {
        printElementPath((ElkGraphElement) element.eContainer(), builder);
        builder.append(" > ");
    } else {
        builder.append("Root ");
    }
    // Print the class name
    String className = element.eClass().getName();
    if (className.startsWith("Elk")) {
        // CHECKSTYLEOFF MagicNumber
        builder.append(className.substring(3));
    // CHECKSTYLEON MagicNumber
    } else {
        builder.append(className);
    }
    // Print the identifier if present
    String identifier = element.getIdentifier();
    if (!Strings.isNullOrEmpty(identifier)) {
        builder.append(' ').append(identifier);
        return;
    }
    // Print the label if present
    if (element instanceof ElkLabel) {
        String text = ((ElkLabel) element).getText();
        if (!Strings.isNullOrEmpty(text)) {
            builder.append(' ').append(text);
            return;
        }
    }
    for (ElkLabel label : element.getLabels()) {
        String text = label.getText();
        if (!Strings.isNullOrEmpty(text)) {
            builder.append(' ').append(text);
            return;
        }
    }
    // If it's an edge and no identifier nor label is present, print source and target
    if (element instanceof ElkEdge) {
        ElkEdge edge = (ElkEdge) element;
        if (edge.isConnected()) {
            builder.append(" (");
            ListIterator<ElkConnectableShape> sourceIter = edge.getSources().listIterator();
            while (sourceIter.hasNext()) {
                if (sourceIter.nextIndex() > 0) {
                    builder.append(", ");
                }
                printElementPath(sourceIter.next(), builder);
            }
            builder.append(" -> ");
            ListIterator<ElkConnectableShape> targetIter = edge.getTargets().listIterator();
            while (targetIter.hasNext()) {
                if (targetIter.nextIndex() > 0) {
                    builder.append(", ");
                }
                printElementPath(targetIter.next(), builder);
            }
            builder.append(")");
        }
    }
}
Also used : ElkLabel(org.eclipse.elk.graph.ElkLabel) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 25 with ElkEdge

use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.

the class FixedLayoutProvider method layout.

@Override
public void layout(final ElkNode layoutNode, final IElkProgressMonitor progressMonitor) {
    progressMonitor.begin("Fixed Layout", 1);
    EdgeRouting edgeRouting = layoutNode.getProperty(CoreOptions.EDGE_ROUTING);
    double maxx = 0;
    double maxy = 0;
    for (ElkNode node : layoutNode.getChildren()) {
        // set the fixed position of the node, or leave it as it is
        KVector pos = node.getProperty(FixedLayouterOptions.POSITION);
        if (pos != null) {
            node.setLocation(pos.x, pos.y);
            // set the fixed size of the node
            if (node.getProperty(FixedLayouterOptions.NODE_SIZE_CONSTRAINTS).contains(SizeConstraint.MINIMUM_SIZE)) {
                KVector minSize = node.getProperty(FixedLayouterOptions.NODE_SIZE_MINIMUM);
                if (minSize.x > 0 && minSize.y > 0) {
                    ElkUtil.resizeNode(node, minSize.x, minSize.y, true, true);
                }
            }
        }
        maxx = Math.max(maxx, node.getX() + node.getWidth());
        maxy = Math.max(maxy, node.getY() + node.getHeight());
        // set the fixed position of the node labels, or leave them as they are
        for (ElkLabel label : node.getLabels()) {
            pos = label.getProperty(FixedLayouterOptions.POSITION);
            if (pos != null) {
                label.setLocation(pos.x, pos.y);
            }
            maxx = Math.max(maxx, node.getX() + label.getX() + label.getWidth());
            maxy = Math.max(maxy, node.getY() + label.getY() + label.getHeight());
        }
        // set the fixed position of the ports, or leave them as they are
        for (ElkPort port : node.getPorts()) {
            pos = port.getProperty(FixedLayouterOptions.POSITION);
            if (pos != null) {
                port.setLocation(pos.x, pos.y);
            }
            double portx = node.getX() + port.getX();
            double porty = node.getY() + port.getY();
            maxx = Math.max(maxx, portx + port.getWidth());
            maxy = Math.max(maxy, porty + port.getHeight());
            // set the fixed position of the port labels, or leave them as they are
            for (ElkLabel label : port.getLabels()) {
                pos = label.getProperty(FixedLayouterOptions.POSITION);
                if (pos != null) {
                    label.setLocation(pos.x, pos.y);
                }
                maxx = Math.max(maxx, portx + label.getX() + label.getWidth());
                maxy = Math.max(maxy, porty + label.getY() + label.getHeight());
            }
        }
        // set fixed routing for the node's outgoing edges (both simple and hierarchical), or leave them as they are
        for (ElkEdge edge : ElkGraphUtil.allOutgoingEdges(node)) {
            KVector maxv = processEdge(edge, edgeRouting);
            maxx = Math.max(maxx, maxv.x);
            maxy = Math.max(maxy, maxv.y);
        }
        // note that this potentially results in hierarchical edges being handled twice
        for (ElkEdge edge : ElkGraphUtil.allIncomingEdges(node)) {
            if (ElkGraphUtil.getSourceNode(edge).getParent() != layoutNode) {
                KVector maxv = processEdge(edge, edgeRouting);
                maxx = Math.max(maxx, maxv.x);
                maxy = Math.max(maxy, maxv.y);
            }
        }
    }
    // if orthogonal routing is selected, determine the junction points
    if (edgeRouting == EdgeRouting.ORTHOGONAL) {
        for (ElkNode node : layoutNode.getChildren()) {
            for (ElkEdge edge : ElkGraphUtil.allOutgoingEdges(node)) {
                generateJunctionPoints(edge);
            }
        }
    }
    // set size of the parent node unless its size should be fixed as well
    if (!layoutNode.getProperty(FixedLayouterOptions.NODE_SIZE_FIXED_GRAPH_SIZE)) {
        ElkPadding padding = layoutNode.getProperty(FixedLayouterOptions.PADDING);
        double newWidth = maxx + padding.getLeft() + padding.getRight();
        double newHeight = maxy + padding.getTop() + padding.getBottom();
        ElkUtil.resizeNode(layoutNode, newWidth, newHeight, true, true);
    }
    progressMonitor.done();
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) ElkLabel(org.eclipse.elk.graph.ElkLabel) ElkPort(org.eclipse.elk.graph.ElkPort) EdgeRouting(org.eclipse.elk.core.options.EdgeRouting) KVector(org.eclipse.elk.core.math.KVector) ElkPadding(org.eclipse.elk.core.math.ElkPadding) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Aggregations

ElkEdge (org.eclipse.elk.graph.ElkEdge)73 ElkNode (org.eclipse.elk.graph.ElkNode)59 ElkPort (org.eclipse.elk.graph.ElkPort)27 KVector (org.eclipse.elk.core.math.KVector)23 ElkEdgeSection (org.eclipse.elk.graph.ElkEdgeSection)21 ElkLabel (org.eclipse.elk.graph.ElkLabel)20 ElkConnectableShape (org.eclipse.elk.graph.ElkConnectableShape)10 LinkedList (java.util.LinkedList)9 ElkBendPoint (org.eclipse.elk.graph.ElkBendPoint)9 ElkGraphElement (org.eclipse.elk.graph.ElkGraphElement)9 SizeConstraint (org.eclipse.elk.core.options.SizeConstraint)8 Test (org.junit.Test)8 ArrayList (java.util.ArrayList)7 List (java.util.List)6 ElkPadding (org.eclipse.elk.core.math.ElkPadding)6 KVectorChain (org.eclipse.elk.core.math.KVectorChain)5 HashSet (java.util.HashSet)4 Lists (com.google.common.collect.Lists)3 Collection (java.util.Collection)3 Set (java.util.Set)3