use of org.eclipse.elk.core.alg.ILayoutProcessor in project elk by eclipse.
the class RadialLayoutProvider method layout.
@Override
public void layout(final ElkNode layoutGraph, final IElkProgressMonitor progressMonitor) {
List<ILayoutProcessor<ElkNode>> algorithm = assembleAlgorithm(layoutGraph);
progressMonitor.begin("Radial layout", algorithm.size());
// if requested, compute nodes's dimensions, place node labels, ports, port labels, etc.
if (!layoutGraph.getProperty(RadialOptions.OMIT_NODE_MICRO_LAYOUT)) {
NodeMicroLayout.forGraph(layoutGraph).execute();
}
// pre calculate the root node and save it
ElkNode root = RadialUtil.findRoot(layoutGraph);
layoutGraph.setProperty(InternalProperties.ROOT_NODE, root);
if (root == null) {
throw new IllegalArgumentException("The given graph is not a tree!");
}
// Calculate the radius or take the one given by the user.
double layoutRadius = layoutGraph.getProperty(RadialOptions.RADIUS);
if (layoutRadius == 0) {
layoutRadius = RadialUtil.findLargestNodeInGraph(layoutGraph);
}
layoutGraph.setProperty(RadialOptions.RADIUS, layoutRadius);
// execute the different phases
for (ILayoutProcessor<ElkNode> processor : assembleAlgorithm(layoutGraph)) {
processor.process(layoutGraph, progressMonitor.subTask(1));
}
progressMonitor.done();
}
use of org.eclipse.elk.core.alg.ILayoutProcessor 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.core.alg.ILayoutProcessor 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.core.alg.ILayoutProcessor 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.core.alg.ILayoutProcessor in project elk by eclipse.
the class ElkLayered method runLayoutTestUntil.
/**
* Runs the algorithm on the current test graphs up to the point where the given phase or
* processor has finished executing. If parts of the algorithm were already executed using this
* or other layout test methods, execution is resumed from there. If the given phase or
* processor is not among those processors that have not yet executed, an exception is thrown.
* Also, if there is no current layout test run, an exception is thrown.
*
* @param phase the phase or processor to stop after
* @param inclusive {@code true} if the specified phase should be executed as well
* @param state the current test execution state
* @throws IllegalArgumentException
* if the given layout processor is not part of the processors that are still to be
* executed.
*/
public void runLayoutTestUntil(final Class<? extends ILayoutProcessor<LGraph>> phase, final boolean inclusive, final TestExecutionState state) {
List<ILayoutProcessor<LGraph>> algorithm = state.graphs.get(0).getProperty(InternalProperties.PROCESSORS);
// check if the given phase exists in our current algorithm configuration
boolean phaseExists = false;
ListIterator<ILayoutProcessor<LGraph>> algorithmIterator = algorithm.listIterator(state.step);
int phaseIndex = state.step;
while (algorithmIterator.hasNext() && !phaseExists) {
if (algorithmIterator.next().getClass().equals(phase)) {
phaseExists = true;
if (inclusive) {
phaseIndex++;
}
} else {
phaseIndex++;
}
}
if (!phaseExists) {
// FIXME actually, we want to know when a processor is not
// part of the algorithm's configuration because this might be
// wrong behavior.
// However, in the current test framework there is no way
// to differentiate between 'it's ok' and 'it's not'.
// throw new IllegalArgumentException(
// "Given processor not part of the remaining algorithm.");
System.err.println("Given processor " + phase + " not part of the remaining algorithm.");
}
// perform the layout up to and including that phase
algorithmIterator = algorithm.listIterator(state.step);
for (; state.step < phaseIndex; state.step++) {
layoutTest(state.graphs, algorithmIterator.next());
}
}
Aggregations