Search in sources :

Example 16 with LGraph

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

the class LayeredLayoutProvider method startLayoutTest.

// /////////////////////////////////////////////////////////////////////////////
// Layout Testing
/**
 * Import the given KGraph and return a test execution state prepared for a test run with the
 * resulting {@link LGraph}. The layout test run methods can immediately be called on the
 * returned object.
 *
 * <p><strong>Note:</strong> This method does not apply the layout back to the original KGraph!</p>
 *
 * @param elkgraph the KGraph to be used for the layout test run.
 * @return an initialized test execution state
 */
public ElkLayered.TestExecutionState startLayoutTest(final ElkNode elkgraph) {
    // Import the graph (layeredGraph won't be null since the KGraphImporter always returns an
    // LGraph instance, even though the IGraphImporter interface would allow null as a return
    // value)
    IGraphTransformer<ElkNode> graphImporter = new ElkGraphTransformer();
    LGraph layeredGraph = graphImporter.importGraph(elkgraph);
    // Prepare a layout test and return the test execution state
    return elkLayered.prepareLayoutTest(layeredGraph);
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) ElkGraphTransformer(org.eclipse.elk.alg.layered.graph.transform.ElkGraphTransformer) LGraph(org.eclipse.elk.alg.layered.graph.LGraph)

Example 17 with LGraph

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

the class LayerSweepCrossingMinimizer method initialize.

/**
 * Traverses inclusion breadth-first and initializes each Graph.
 */
private List<GraphInfoHolder> initialize(final LGraph rootGraph) {
    graphInfoHolders = Lists.newArrayList();
    random = rootGraph.getProperty(InternalProperties.RANDOM);
    randomSeed = random.nextLong();
    List<GraphInfoHolder> graphsToSweepOn = Lists.newLinkedList();
    List<LGraph> graphs = Lists.<LGraph>newArrayList(rootGraph);
    int i = 0;
    while (i < graphs.size()) {
        LGraph graph = graphs.get(i);
        graph.id = i++;
        GraphInfoHolder gData = new GraphInfoHolder(graph, crossMinType, graphInfoHolders);
        graphs.addAll(gData.childGraphs());
        graphInfoHolders.add(gData);
        if (gData.dontSweepInto()) {
            graphsToSweepOn.add(0, gData);
        }
    }
    graphsWhoseNodeOrderChanged = Sets.newHashSet();
    return graphsToSweepOn;
}
Also used : LGraph(org.eclipse.elk.alg.layered.graph.LGraph)

Example 18 with LGraph

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

the class ElkGraphImporter method importGraph.

// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Import Entry Points
/**
 * Imports the given graph.
 *
 * @param elkgraph
 *            the graph to import.
 * @return the transformed graph.
 */
public LGraph importGraph(final ElkNode elkgraph) {
    // Create the layered graph
    final LGraph topLevelGraph = createLGraph(elkgraph);
    // Assign defined port sides to all external ports
    elkgraph.getPorts().stream().forEach(elkport -> ensureDefinedPortSide(topLevelGraph, elkport));
    // Transform the external ports, if any
    Set<GraphProperties> graphProperties = topLevelGraph.getProperty(InternalProperties.GRAPH_PROPERTIES);
    checkExternalPorts(elkgraph, graphProperties);
    if (graphProperties.contains(GraphProperties.EXTERNAL_PORTS)) {
        for (ElkPort elkport : elkgraph.getPorts()) {
            transformExternalPort(elkgraph, topLevelGraph, elkport);
        }
    }
    // Calculate the graph's minimum size
    if (shouldCalculateMinimumGraphSize(elkgraph)) {
        calculateMinimumGraphSize(elkgraph, topLevelGraph);
    }
    // Remember things
    if (topLevelGraph.getProperty(LayeredOptions.PARTITIONING_ACTIVATE)) {
        graphProperties.add(GraphProperties.PARTITIONS);
    }
    // values of the first layout run would be used (explicitly set spacing values are not overwritten).
    if (topLevelGraph.hasProperty(LayeredOptions.SPACING_BASE_VALUE)) {
        LayeredSpacings.withBaseValue(topLevelGraph.getProperty(LayeredOptions.SPACING_BASE_VALUE)).apply(topLevelGraph);
    }
    // Import the graph either with or without multiple nested levels of hierarchy
    if (elkgraph.getProperty(LayeredOptions.HIERARCHY_HANDLING) == HierarchyHandling.INCLUDE_CHILDREN) {
        importHierarchicalGraph(elkgraph, topLevelGraph);
    } else {
        importFlatGraph(elkgraph, topLevelGraph);
    }
    return topLevelGraph;
}
Also used : GraphProperties(org.eclipse.elk.alg.layered.options.GraphProperties) ElkPort(org.eclipse.elk.graph.ElkPort) LGraph(org.eclipse.elk.alg.layered.graph.LGraph)

Example 19 with LGraph

use of org.eclipse.elk.alg.layered.graph.LGraph 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 20 with LGraph

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

the class ComponentsCompactor method compact.

// ------------------------------------------------------------------------------------------------
// public API
// ------------------------------------------------------------------------------------------------
/**
 * @param graphs
 *            the components to be compacted
 * @param originalGraphsSize
 *            the size of the overall graph as it is currently
 * @param spacing
 *            the desired spacing to be preserved between any pair of components
 */
public void compact(final List<LGraph> graphs, final KVector originalGraphsSize, final double spacing) {
    // determine the extreme points of the current diagram,
    // we will reuse this 'frame' to cut external extensions at appropriate lengths
    graphTopLeft = new KVector(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
    graphBottomRight = new KVector(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
    for (LGraph graph : graphs) {
        for (LNode node : graph.getLayerlessNodes()) {
            graphTopLeft.x = Math.min(graphTopLeft.x, node.getPosition().x - node.getMargin().left);
            graphTopLeft.y = Math.min(graphTopLeft.y, node.getPosition().y - node.getMargin().top);
            graphBottomRight.x = Math.max(graphBottomRight.x, node.getPosition().x + node.getSize().x + node.getMargin().right);
            graphBottomRight.y = Math.max(graphBottomRight.y, node.getPosition().y + node.getSize().y + node.getMargin().bottom);
        }
    }
    // from the lgraphs, create connected components
    IConnectedComponents<LNode, Set<LEdge>> ccs = new InternalConnectedComponents();
    for (LGraph graph : graphs) {
        IComponent<LNode, Set<LEdge>> c = transformLGraph(graph);
        ccs.getComponents().add(c);
        ((InternalComponent) c).containsRegularNodes |= !c.getExternalExtensionSides().isEmpty();
    }
    // for every component we create an element in the compactor
    compactor = OneDimensionalComponentsCompaction.init(ccs, spacing);
    // execute compaction
    compactor.compact(new BasicProgressMonitor());
    yetAnotherOffset = new KVector();
    compactedGraphSize = compactor.getGraphSize();
    // apply the positions
    for (IComponent<LNode, Set<LEdge>> cc : ccs.getComponents()) {
        // retrieve the common offset for the currently handled connected component
        KVector offset = compactor.getOffset(cc);
        // move it
        LGraphUtil.offsetGraph(((InternalComponent) cc).graph, offset.x, offset.y);
        // adjust positions of external ports
        for (LNode n : ((InternalComponent) cc).getNodes()) {
            if (n.getType() == NodeType.EXTERNAL_PORT) {
                KVector newPos = getExternalPortPosition(n.getPosition(), n.getProperty(InternalProperties.EXT_PORT_SIDE));
                n.getPosition().reset().add(newPos);
            }
        }
    }
    // external edges contribute to the graph's size ... however, only certain segments do.
    for (IComponent<LNode, Set<LEdge>> cc : ccs.getComponents()) {
        for (LEdge e : ((InternalComponent) cc).getExternalEdges()) {
            KVectorChain vc = new KVectorChain(e.getBendPoints());
            vc.add(0, e.getSource().getAbsoluteAnchor());
            vc.add(e.getTarget().getAbsoluteAnchor());
            KVector last = null;
            for (KVector v : vc) {
                if (last == null) {
                    last = v;
                    continue;
                }
                if (DoubleMath.fuzzyEquals(last.x, v.x, EPSILON)) {
                    yetAnotherOffset.x = Math.min(yetAnotherOffset.x, last.x);
                    compactedGraphSize.x = Math.max(compactedGraphSize.x, last.x);
                } else if (DoubleMath.fuzzyEquals(last.y, v.y, EPSILON)) {
                    yetAnotherOffset.y = Math.min(yetAnotherOffset.y, last.y);
                    compactedGraphSize.y = Math.max(compactedGraphSize.y, last.y);
                }
                last = v;
            }
        }
    }
    yetAnotherOffset.negate();
    compactedGraphSize.add(yetAnotherOffset);
}
Also used : Set(java.util.Set) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) BasicProgressMonitor(org.eclipse.elk.core.util.BasicProgressMonitor)

Aggregations

LGraph (org.eclipse.elk.alg.layered.graph.LGraph)115 LNode (org.eclipse.elk.alg.layered.graph.LNode)90 LPort (org.eclipse.elk.alg.layered.graph.LPort)49 Layer (org.eclipse.elk.alg.layered.graph.Layer)38 Test (org.junit.Test)36 TestAfterProcessor (org.eclipse.elk.alg.test.framework.annotations.TestAfterProcessor)19 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)17 KVector (org.eclipse.elk.core.math.KVector)15 InternalProperties (org.eclipse.elk.alg.layered.options.InternalProperties)14 LayeredOptions (org.eclipse.elk.alg.layered.options.LayeredOptions)13 List (java.util.List)11 ILayoutProcessor (org.eclipse.elk.core.alg.ILayoutProcessor)11 IElkProgressMonitor (org.eclipse.elk.core.util.IElkProgressMonitor)10 NodeType (org.eclipse.elk.alg.layered.graph.LNode.NodeType)9 Lists (com.google.common.collect.Lists)7 Set (java.util.Set)7 GraphProperties (org.eclipse.elk.alg.layered.options.GraphProperties)7 GraphInfoHolder (org.eclipse.elk.alg.layered.p3order.GraphInfoHolder)7 PortSide (org.eclipse.elk.core.options.PortSide)7 ElkNode (org.eclipse.elk.graph.ElkNode)7