Search in sources :

Example 11 with LGraph

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

the class ElkLayered method layout.

// //////////////////////////////////////////////////////////////////////////////
// Actual Layout
/**
 * Perform the five phases of the layered layouter.
 *
 * @param lgraph the graph that is to be laid out
 * @param monitor a progress monitor
 */
private void layout(final LGraph lgraph, final IElkProgressMonitor monitor) {
    boolean monitorWasAlreadyRunning = monitor.isRunning();
    if (!monitorWasAlreadyRunning) {
        monitor.begin("Component Layout", 1);
    }
    List<ILayoutProcessor<LGraph>> algorithm = lgraph.getProperty(InternalProperties.PROCESSORS);
    float monitorProgress = 1.0f / algorithm.size();
    if (monitor.isLoggingEnabled()) {
        // Print the algorithm configuration
        monitor.log("ELK Layered uses the following " + algorithm.size() + " modules:");
        int slot = 0;
        for (ILayoutProcessor<LGraph> processor : algorithm) {
            // SUPPRESS CHECKSTYLE NEXT MagicNumber
            String gwtDoesntSupportPrintf = (slot < 10 ? "0" : "") + (slot++);
            monitor.log("   Slot " + gwtDoesntSupportPrintf + ": " + processor.getClass().getName());
        }
    }
    // Invoke each layout processor
    int slotIndex = 0;
    for (ILayoutProcessor<LGraph> processor : algorithm) {
        if (monitor.isCanceled()) {
            return;
        }
        // elkjs-exclude-start
        if (monitor.isLoggingEnabled()) {
            DebugUtil.logDebugGraph(monitor, lgraph, slotIndex, "Before " + processor.getClass().getSimpleName());
        }
        // elkjs-exclude-end
        notifyProcessorReady(lgraph, processor);
        processor.process(lgraph, monitor.subTask(monitorProgress));
        notifyProcessorFinished(lgraph, processor);
        slotIndex++;
    }
    // elkjs-exclude-start
    if (monitor.isLoggingEnabled()) {
        DebugUtil.logDebugGraph(monitor, lgraph, slotIndex, "Finished");
    }
    // second loop to avoid ConcurrentModificationExceptions)
    for (Layer layer : lgraph) {
        lgraph.getLayerlessNodes().addAll(layer.getNodes());
        layer.getNodes().clear();
    }
    for (LNode node : lgraph.getLayerlessNodes()) {
        node.setLayer(null);
    }
    lgraph.getLayers().clear();
    if (!monitorWasAlreadyRunning) {
        monitor.done();
    }
}
Also used : ILayoutProcessor(org.eclipse.elk.core.alg.ILayoutProcessor) LNode(org.eclipse.elk.alg.layered.graph.LNode) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) Layer(org.eclipse.elk.alg.layered.graph.Layer) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint)

Example 12 with LGraph

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

the class ElkLayered method isLayoutTestFinished.

/**
 * Checks if the current test run still has processors to be executed for the algorithm to finish.
 *
 * @param state the current test execution state
 * @return {@code true} if the current test run has not finished yet. If there is no current
 *         test run, the result is undefined.
 */
public boolean isLayoutTestFinished(final TestExecutionState state) {
    LGraph graph = state.graphs.get(0);
    List<ILayoutProcessor<LGraph>> algorithm = graph.getProperty(InternalProperties.PROCESSORS);
    return algorithm != null && state.step >= algorithm.size();
}
Also used : ILayoutProcessor(org.eclipse.elk.core.alg.ILayoutProcessor) LGraph(org.eclipse.elk.alg.layered.graph.LGraph)

Example 13 with LGraph

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

the class ElkLayered method doLayout.

// //////////////////////////////////////////////////////////////////////////////
// Regular Layout
/**
 * Does a layout on the given graph. If the graph contains compound nodes (see class documentation),
 * the nested graphs are ignored.
 *
 * @param lgraph the graph to layout
 * @param monitor a progress monitor to show progress information in, or {@code null}
 * @see #doCompoundLayout(LGraph, IElkProgressMonitor)
 */
public void doLayout(final LGraph lgraph, final IElkProgressMonitor monitor) {
    IElkProgressMonitor theMonitor = monitor;
    if (theMonitor == null) {
        theMonitor = new BasicProgressMonitor().withMaxHierarchyLevels(0);
    }
    theMonitor.begin("Layered layout", 1);
    // Update the modules depending on user options
    graphConfigurator.prepareGraphForLayout(lgraph);
    // Split the input graph into components and perform layout on them
    List<LGraph> components = componentsProcessor.split(lgraph);
    if (components.size() == 1) {
        // Execute layout on the sole component using the top-level progress monitor
        layout(components.get(0), theMonitor);
    } else {
        // Execute layout on each component using a progress monitor subtask
        float compWork = 1.0f / components.size();
        for (LGraph comp : components) {
            if (monitor.isCanceled()) {
                return;
            }
            layout(comp, theMonitor.subTask(compWork));
        }
    }
    componentsProcessor.combine(components, lgraph);
    // Resize the resulting graph, according to minimal size constraints and such
    resizeGraph(lgraph);
    theMonitor.done();
}
Also used : IElkProgressMonitor(org.eclipse.elk.core.util.IElkProgressMonitor) BasicProgressMonitor(org.eclipse.elk.core.util.BasicProgressMonitor) LGraph(org.eclipse.elk.alg.layered.graph.LGraph)

Example 14 with LGraph

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

the class ElkLayered method hierarchicalLayout.

/**
 * Processors can be marked as operating on the full hierarchy by using the {@link IHierarchyAwareLayoutProcessor}
 * interface.
 *
 * All graphs are collected using a breadth-first search and this list is reversed, so that for each graph, all
 * following graphs are on the same hierarchy level or higher, i.e. closer to the parent graph. Each graph then has
 * a unique configuration of ELK Layered, which is comprised of a sequence of processors. The processors can vary
 * depending on the characteristics of each graph. The list of graphs and their algorithms is then traversed. If a
 * processor is not hierarchical it is simply executed. If it it is hierarchical and this graph is not the root
 * graph, this processor is skipped and the algorithm is paused until the processor has been executed on the root
 * graph. Then the algorithm is continued, starting with the level lowest in the hierarchy, i.e. furthest away from
 * the root graph.
 */
private void hierarchicalLayout(final LGraph lgraph, final IElkProgressMonitor monitor) {
    // Perform a reversed breadth first search: The graphs in the lowest hierarchy come first.
    Collection<LGraph> graphs = collectAllGraphsBottomUp(lgraph);
    // We have to make sure that hierarchical processors don't break the control flow
    // of the following layout execution (see e.g. #228). To be precise, if the root node of
    // the hierarchical graph doesn't include a hierarchical processor, nor may any of the children.
    reviewAndCorrectHierarchicalProcessors(lgraph, graphs);
    // Get list of processors for each graph, since they can be different.
    // Iterators are used, so that processing of a graph can be paused and continued easily.
    int work = 0;
    List<Pair<LGraph, Iterator<ILayoutProcessor<LGraph>>>> graphsAndAlgorithms = new ArrayList<>();
    for (LGraph g : graphs) {
        graphConfigurator.prepareGraphForLayout(g);
        List<ILayoutProcessor<LGraph>> processors = g.getProperty(InternalProperties.PROCESSORS);
        work += processors.size();
        Iterator<ILayoutProcessor<LGraph>> algorithm = processors.iterator();
        graphsAndAlgorithms.add(Pair.of(g, algorithm));
    }
    monitor.begin("Recursive hierarchical layout", work);
    // When the root graph has finished layout, the layout is complete.
    int slotIndex = 0;
    Iterator<ILayoutProcessor<LGraph>> rootProcessors = getProcessorsForRootGraph(graphsAndAlgorithms);
    while (rootProcessors.hasNext()) {
        // Layout from bottom up
        for (Pair<LGraph, Iterator<ILayoutProcessor<LGraph>>> graphAndAlgorithm : graphsAndAlgorithms) {
            Iterator<ILayoutProcessor<LGraph>> processors = graphAndAlgorithm.getSecond();
            LGraph graph = graphAndAlgorithm.getFirst();
            while (processors.hasNext()) {
                ILayoutProcessor<LGraph> processor = processors.next();
                if (!(processor instanceof IHierarchyAwareLayoutProcessor)) {
                    // elkjs-exclude-start
                    if (monitor.isLoggingEnabled()) {
                        DebugUtil.logDebugGraph(monitor, graph, slotIndex, "Before " + processor.getClass().getSimpleName());
                    }
                    // elkjs-exclude-end
                    notifyProcessorReady(graph, processor);
                    processor.process(graph, monitor.subTask(1));
                    notifyProcessorFinished(graph, processor);
                    slotIndex++;
                } else if (isRoot(graph)) {
                    // elkjs-exclude-start
                    if (monitor.isLoggingEnabled()) {
                        DebugUtil.logDebugGraph(monitor, graph, slotIndex, "Before " + processor.getClass().getSimpleName());
                    }
                    // elkjs-exclude-end
                    // If processor operates on the full hierarchy, it must be executed on the root
                    notifyProcessorReady(graph, processor);
                    processor.process(graph, monitor.subTask(1));
                    notifyProcessorFinished(graph, processor);
                    slotIndex++;
                    // Continue operation with the graph at the bottom of the hierarchy
                    break;
                } else {
                    // skip this processor and pause execution until root graph has processed.
                    break;
                }
            }
        }
    }
    // elkjs-exclude-start
    if (monitor.isLoggingEnabled()) {
        DebugUtil.logDebugGraph(monitor, lgraph, slotIndex, "Finished");
    }
    // elkjs-exclude-end
    monitor.done();
}
Also used : ILayoutProcessor(org.eclipse.elk.core.alg.ILayoutProcessor) ArrayList(java.util.ArrayList) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) ListIterator(java.util.ListIterator) Iterator(java.util.Iterator) Pair(org.eclipse.elk.core.util.Pair)

Example 15 with LGraph

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

the class GraphConfigurator method getPhaseIndependentLayoutProcessorConfiguration.

/**
 * Returns an intermediate processing configuration with processors not tied to specific phases.
 *
 * @param lgraph the layered graph to be processed. The configuration may vary depending on certain
 *               properties of the graph.
 * @return intermediate processing configuration. May be {@code null}.
 */
private LayoutProcessorConfiguration<LayeredPhases, LGraph> getPhaseIndependentLayoutProcessorConfiguration(final LGraph lgraph) {
    Set<GraphProperties> graphProperties = lgraph.getProperty(InternalProperties.GRAPH_PROPERTIES);
    // Basic configuration
    LayoutProcessorConfiguration<LayeredPhases, LGraph> configuration = LayoutProcessorConfiguration.createFrom(BASELINE_PROCESSING_CONFIGURATION);
    // Hierarchical layout.
    // Note that the recursive graph layout engine made sure that at this point
    // 'INCLUDE_CHILDREN' has been propagated to all parent nodes with 'INHERIT'.
    // Thus, every lgraph of the hierarchical lgraph structure is configured with the following additions.
    HierarchyHandling hierarchyHandling = lgraph.getProperty(LayeredOptions.HIERARCHY_HANDLING);
    if (hierarchyHandling == HierarchyHandling.INCLUDE_CHILDREN) {
        configuration.addAll(HIERARCHICAL_ADDITIONS);
    }
    // Port side processor, put to first slot only if requested and routing is orthogonal
    if (lgraph.getProperty(LayeredOptions.FEEDBACK_EDGES)) {
        configuration.addBefore(LayeredPhases.P1_CYCLE_BREAKING, IntermediateProcessorStrategy.PORT_SIDE_PROCESSOR);
    } else {
        configuration.addBefore(LayeredPhases.P3_NODE_ORDERING, IntermediateProcessorStrategy.PORT_SIDE_PROCESSOR);
    }
    // If the graph has a label manager, so add label management additions
    if (lgraph.getProperty(LabelManagementOptions.LABEL_MANAGER) != null) {
        configuration.addAll(LABEL_MANAGEMENT_ADDITIONS);
    }
    // If the graph should be laid out interactively, add the layers and positions to the nodes.
    if (lgraph.getProperty(LayeredOptions.INTERACTIVE_LAYOUT)) {
        configuration.addAfter(LayeredPhases.P5_EDGE_ROUTING, IntermediateProcessorStrategy.CONSTRAINTS_POSTPROCESSOR);
    }
    // graph transformations for unusual layout directions
    switch(lgraph.getProperty(LayeredOptions.DIRECTION)) {
        case LEFT:
        case DOWN:
        case UP:
            configuration.addBefore(LayeredPhases.P1_CYCLE_BREAKING, IntermediateProcessorStrategy.DIRECTION_PREPROCESSOR).addAfter(LayeredPhases.P5_EDGE_ROUTING, IntermediateProcessorStrategy.DIRECTION_POSTPROCESSOR);
            break;
        default:
            // don't need any processors here
            break;
    }
    // Additional dependencies
    if (graphProperties.contains(GraphProperties.COMMENTS)) {
        configuration.addBefore(LayeredPhases.P1_CYCLE_BREAKING, IntermediateProcessorStrategy.COMMENT_PREPROCESSOR).addBefore(LayeredPhases.P4_NODE_PLACEMENT, IntermediateProcessorStrategy.COMMENT_NODE_MARGIN_CALCULATOR).addAfter(LayeredPhases.P5_EDGE_ROUTING, IntermediateProcessorStrategy.COMMENT_POSTPROCESSOR);
    }
    // Node-Promotion application for reduction of dummy nodes after layering
    if (lgraph.getProperty(LayeredOptions.LAYERING_NODE_PROMOTION_STRATEGY) != NodePromotionStrategy.NONE) {
        configuration.addBefore(LayeredPhases.P3_NODE_ORDERING, IntermediateProcessorStrategy.NODE_PROMOTION);
    }
    // Preserve certain partitions during layering
    if (graphProperties.contains(GraphProperties.PARTITIONS)) {
        configuration.addBefore(LayeredPhases.P1_CYCLE_BREAKING, IntermediateProcessorStrategy.PARTITION_PREPROCESSOR);
        configuration.addBefore(LayeredPhases.P2_LAYERING, IntermediateProcessorStrategy.PARTITION_MIDPROCESSOR);
        configuration.addBefore(LayeredPhases.P3_NODE_ORDERING, IntermediateProcessorStrategy.PARTITION_POSTPROCESSOR);
    }
    // Additional horizontal compaction depends on orthogonal edge routing
    if (lgraph.getProperty(LayeredOptions.COMPACTION_POST_COMPACTION_STRATEGY) != GraphCompactionStrategy.NONE && lgraph.getProperty(LayeredOptions.EDGE_ROUTING) != EdgeRouting.POLYLINE) {
        configuration.addAfter(LayeredPhases.P5_EDGE_ROUTING, IntermediateProcessorStrategy.HORIZONTAL_COMPACTOR);
    }
    // Move trees of high degree nodes to separate layers
    if (lgraph.getProperty(LayeredOptions.HIGH_DEGREE_NODES_TREATMENT)) {
        configuration.addBefore(LayeredPhases.P3_NODE_ORDERING, IntermediateProcessorStrategy.HIGH_DEGREE_NODE_LAYER_PROCESSOR);
    }
    // Introduce in-layer constraints to preserve the order of regular nodes
    if (lgraph.getProperty(LayeredOptions.CROSSING_MINIMIZATION_SEMI_INTERACTIVE)) {
        configuration.addBefore(LayeredPhases.P3_NODE_ORDERING, IntermediateProcessorStrategy.SEMI_INTERACTIVE_CROSSMIN_PROCESSOR);
    }
    // ElkLayered#reviewAndCorrectHierarchicalProcessors(...)
    if (activateGreedySwitchFor(lgraph)) {
        final GreedySwitchType greedySwitchType;
        if (isHierarchicalLayout(lgraph)) {
            greedySwitchType = lgraph.getProperty(LayeredOptions.CROSSING_MINIMIZATION_GREEDY_SWITCH_HIERARCHICAL_TYPE);
        } else {
            greedySwitchType = lgraph.getProperty(LayeredOptions.CROSSING_MINIMIZATION_GREEDY_SWITCH_TYPE);
        }
        IntermediateProcessorStrategy internalGreedyType = (greedySwitchType == GreedySwitchType.ONE_SIDED) ? IntermediateProcessorStrategy.ONE_SIDED_GREEDY_SWITCH : IntermediateProcessorStrategy.TWO_SIDED_GREEDY_SWITCH;
        configuration.addBefore(LayeredPhases.P4_NODE_PLACEMENT, internalGreedyType);
    }
    // Wrapping of graphs
    switch(lgraph.getProperty(LayeredOptions.WRAPPING_STRATEGY)) {
        case SINGLE_EDGE:
            configuration.addBefore(LayeredPhases.P4_NODE_PLACEMENT, IntermediateProcessorStrategy.SINGLE_EDGE_GRAPH_WRAPPER);
            break;
        case MULTI_EDGE:
            configuration.addBefore(LayeredPhases.P3_NODE_ORDERING, IntermediateProcessorStrategy.BREAKING_POINT_INSERTER).addBefore(LayeredPhases.P4_NODE_PLACEMENT, IntermediateProcessorStrategy.BREAKING_POINT_PROCESSOR).addAfter(LayeredPhases.P5_EDGE_ROUTING, IntermediateProcessorStrategy.BREAKING_POINT_REMOVER);
            break;
        // OFF
        default:
    }
    if (lgraph.getProperty(LayeredOptions.CONSIDER_MODEL_ORDER_STRATEGY) != OrderingStrategy.NONE) {
        configuration.addBefore(LayeredPhases.P3_NODE_ORDERING, IntermediateProcessorStrategy.SORT_BY_INPUT_ORDER_OF_MODEL);
    }
    return configuration;
}
Also used : HierarchyHandling(org.eclipse.elk.core.options.HierarchyHandling) GraphProperties(org.eclipse.elk.alg.layered.options.GraphProperties) GreedySwitchType(org.eclipse.elk.alg.layered.options.GreedySwitchType) IntermediateProcessorStrategy(org.eclipse.elk.alg.layered.intermediate.IntermediateProcessorStrategy) LGraph(org.eclipse.elk.alg.layered.graph.LGraph)

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