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();
}
}
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();
}
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();
}
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();
}
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;
}
Aggregations