blob: 7aabbc7b96cc9c1d285a7261ebfa94ae24c4aaed [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" type="image/svg+xml" href="img/elk_fav.svg">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" href="https://www.eclipse.org/elk/css/elk.css">
<link rel="stylesheet" href="https://www.eclipse.org/elk/css/prism.css">
<title>Structuring Algorithms (ELK)</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark">
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="https://www.eclipse.org/elk/">
<img src="img/elk_small_light.svg" height="30" class="d-inline-block align-top mr-1" alt="">
Eclipse Layout Kernel
</a>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="../../../downloads.html">Downloads</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../../../gettingstarted.html">Getting Started</a>
</li>
<li class="nav-item active">
<a class="nav-link" href="../../../documentation.html">Documentation <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="../../../reference.html">Reference</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../../../support.html">Support</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/eclipse/elk">GitHub</a>
</li>
</ul>
</div>
</nav>
<div class="container px-3 py-5">
<div class="row">
<div class="col-sm-9">
<h1>Structuring Algorithms</h1>
<p>Often enough, algorithms can be divided into a number of <em>layout phases</em> which, executed as a pipeline, compute a layout. If your algorithm falls into this category, read on; ELK provides things you might want to use.</p>
<h2 id="layout-phases-and-layout-processors">Layout Phases and Layout Processors</h2>
<p>Structuring the algorithm into phases has several advantages. First, it effectively divides the big layout problem into simpler sub problems. Second, it allows the algorithm to be more flexible. Since the division into phases already forces developers to think about what exactly each phase does, it is easy to add different implementations for each phase for clients to switch between. ELK Layered, for example, implements different edge routing styles (polylines, orthogonal routing, or splines) as different implementations of its edge routing phase.</p>
<p>So far, the algorithm is composed of a pipeline of layout phases. Let&rsquo;s take this concept one step further: what stops us from inserting pre or post processing in between the phases? If we add <em>intermediate processing slots</em> before, between, and after the layout phases, we arrive at the following structure:</p>
<p>
<img
class="img-fluid"
src="../../../img/architecture_phases.png"
alt="Algorithms can be structured into phases and layout processors."
style = "max-height: 500px; display: block;
margin-left: auto;
margin-right: auto;"
/>
</p>
<p>Each processing slot can hold an arbitrary number of <em>intermediate processors</em>, also called <em>layout processors</em>, but what for? Imagine that your algorithm&rsquo;s first phase needs to eliminate cycles in the input graph by reversing edges. Of course, the edges need to be restored to their original direction once the algorithm has finished. If we only had layout phases, the last phase would be responsible for doing so. With intermediate processors, the first phase can simply request a processors to be executed in the last processing slot that restores edges to their original position. This way of doing things has two advantages. First, the processor has a well-defined purpose and is easy to implement. Second, if there were several different implementations of the last phase, all of them would have to include code to restore reversed edges, thereby introducing code duplication as well as a possible source for bugs.</p>
<p>This example already highlights a difference between layout phases and layout processors: layout phases can request layout processors to be executed in a specific processing slot. Of course, different layout phase implementations can request different processors, resulting in different pipelines. Also, if multiple processors are to be executed in a pipeline, they usually need to be sorted according to their dependencies. A processor that calculates the amount of space around a node required by labels will need a processor that places these labels to have finished executing.</p>
<h2 id="the-implementation">The Implementation</h2>
<p>ELK contains everything required to implement layout algorithms this way in its <code>org.eclipse.elk.core.alg</code> package. To use that, the first thing you should start with is to write an enumeration that lists all the phases your algorithm will consist of. For example:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> LayoutPhases <span style="color:#f92672">{</span>
P1_TREEIFICATION<span style="color:#f92672">,</span>
P2_NODE_ORDERING<span style="color:#f92672">,</span>
P3_NODE_PLACEMENT<span style="color:#f92672">,</span>
P4_EDGE_ROUTING<span style="color:#f92672">;</span>
<span style="color:#f92672">}</span>
</code></pre></div><h3 id="layout-phases">Layout Phases</h3>
<p>It is now time to start writing your phases. Implementing a layout phase is, in principle, easy: simply have your phase class implement the <code>ILayoutPhase&lt;P, G&gt;</code> interface, where <code>P</code> is the enumeration of layout phases you just wrote, and <code>G</code> is the type of the graph processed by the phase. For example:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">NodeOrderer</span> <span style="color:#66d9ef">implements</span> ILayoutPhase<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#f92672">{</span>
<span style="color:#a6e22e">@Override</span>
<span style="color:#66d9ef">public</span> LayoutProcessorConfiguration<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">getLayoutProcessorConfiguration</span><span style="color:#f92672">(</span>ElkNode graph<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
<span style="color:#75715e">// To start with, the phase won&#39;t require any layout processors
</span><span style="color:#75715e"></span> <span style="color:#66d9ef">return</span> LayoutProcessorConfiguration<span style="color:#f92672">.&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span>create<span style="color:#f92672">();</span>
<span style="color:#f92672">}</span>
<span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">process</span><span style="color:#f92672">(</span>ElkNode ElkNode<span style="color:#f92672">,</span> IElkProgressMonitor progressMonitor<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
<span style="color:#75715e">// This will be the entry point to your phase
</span><span style="color:#75715e"></span> <span style="color:#f92672">}</span>
</code></pre></div><p>Besides the actual implementation in its <code>process(...)</code> method, a layout phase has one other interesting method: <code>getLayoutProcessorConfiguration(...)</code>. We will take a closer look at that a bit later. Before we can do that, we need to take a look at how to implement intermediate processors.</p>
<h3 id="intermediate-processors">Intermediate Processors</h3>
<p>Implementing a layout processor is, again, easy: simply have your processor class implement the <code>ILayoutProcessor&lt;G&gt;</code> interface, where <code>G</code> is the type of the graph processed by the processor. For example:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">RatherExcellentProcessor</span> <span style="color:#66d9ef">implements</span> ILayoutProcessor<span style="color:#f92672">&lt;</span>ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#f92672">{</span>
<span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">process</span><span style="color:#f92672">(</span>ElkNode theGraph<span style="color:#f92672">,</span> IElkProgressMonitor monitor<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
<span style="color:#75715e">// This will be the entry point to your processor
</span><span style="color:#75715e"></span> <span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
</code></pre></div><h3 id="specifying-dependencies-from-phases-to-processors">Specifying Dependencies from Phases to Processors</h3>
<p>Before we can specify dependencies, we will need an enumeration of all available layout processors. In fact, we will need factories to instantiate those processors, but using an enumeration can give us a simple way to implement those. For example:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> IntermediateProcessorStrategy <span style="color:#66d9ef">implements</span> ILayoutProcessorFactory<span style="color:#f92672">&lt;</span>ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#f92672">{</span>
<span style="color:#75715e">// Before Phase 2
</span><span style="color:#75715e"></span> ROOT_PROC<span style="color:#f92672">,</span>
FAN_PROC<span style="color:#f92672">,</span>
NEIGHBORS_PROC<span style="color:#f92672">,</span>
<span style="color:#75715e">// Before Phase 3
</span><span style="color:#75715e"></span> LEVEL_HEIGHT<span style="color:#f92672">,</span>
<span style="color:#75715e">// Before Phase 4
</span><span style="color:#75715e"></span> NODE_POSITION_PROC<span style="color:#f92672">,</span>
<span style="color:#75715e">// After Phase 4
</span><span style="color:#75715e"></span> DETREEIFYING_PROC<span style="color:#f92672">;</span>
<span style="color:#66d9ef">public</span> ILayoutProcessor<span style="color:#f92672">&lt;</span>ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">create</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
<span style="color:#66d9ef">switch</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
<span style="color:#66d9ef">case</span> ROOT_PROC<span style="color:#f92672">:</span>
<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> RootProcessor<span style="color:#f92672">();</span>
<span style="color:#66d9ef">case</span> FAN_PROC<span style="color:#f92672">:</span>
<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> FanProcessor<span style="color:#f92672">();</span>
<span style="color:#66d9ef">case</span> NEIGHBORS_PROC<span style="color:#f92672">:</span>
<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> NeighborsProcessor<span style="color:#f92672">();</span>
<span style="color:#66d9ef">case</span> LEVEL_HEIGHT<span style="color:#f92672">:</span>
<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> LevelHeightProcessor<span style="color:#f92672">();</span>
<span style="color:#66d9ef">case</span> NODE_POSITION_PROC<span style="color:#f92672">:</span>
<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> NodePositionProcessor<span style="color:#f92672">();</span>
<span style="color:#66d9ef">case</span> DETREEIFYING_PROC<span style="color:#f92672">:</span>
<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> Untreeifyer<span style="color:#f92672">();</span>
default:
<span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> IllegalArgumentException<span style="color:#f92672">(</span>
<span style="color:#e6db74">&#34;No implementation is available for the layout processor &#34;</span> <span style="color:#f92672">+</span> <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">toString</span><span style="color:#f92672">());</span>
<span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>We are now ready to specify which layout processors a layout phase needs to be executed in which intermediate processing slots. This is what the phase&rsquo;s <code>getLayoutProcessorConfiguration(...)</code> method is for. That method returns an instance of <code>LayoutProcessorConfiguration&lt;P, G&gt;</code>, which specifies exactly that: the intermediate processors to add to the different processing slots. Which processors are required may well depend on the input graph, which explains why that graph is passed to the method. A simple implementation could look like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> LayoutProcessorConfiguration<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> INTERMEDIATE_PROCESSING_CONFIG <span style="color:#f92672">=</span>
LayoutProcessorConfiguration<span style="color:#f92672">.&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span>create<span style="color:#f92672">()</span>
<span style="color:#f92672">.</span><span style="color:#a6e22e">addBefore</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P2_NODE_ORDERING</span><span style="color:#f92672">,</span> IntermediateProcessorStrategy<span style="color:#f92672">.</span><span style="color:#a6e22e">ROOT_PROC</span><span style="color:#f92672">)</span>
<span style="color:#f92672">.</span><span style="color:#a6e22e">addBefore</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P2_NODE_ORDERING</span><span style="color:#f92672">,</span> IntermediateProcessorStrategy<span style="color:#f92672">.</span><span style="color:#a6e22e">FAN_PROC</span><span style="color:#f92672">);</span>
<span style="color:#a6e22e">@Override</span>
<span style="color:#66d9ef">public</span> LayoutProcessorConfiguration<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">getLayoutProcessorConfiguration</span><span style="color:#f92672">(</span>ElkNode graph<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
<span style="color:#66d9ef">return</span> INTERMEDIATE_PROCESSING_CONFIG<span style="color:#f92672">;</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>This implementation specifies that the processing slot before phase 2 should contain the <code>ROOT_PROC</code> and the <code>FAN_PROC</code> intermediate processors (whatever those are). If multiple processors should be added to the same slots, the following provides a marginally easier way to do so:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> LayoutProcessorConfiguration<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> INTERMEDIATE_PROCESSING_CONFIG <span style="color:#f92672">=</span>
LayoutProcessorConfiguration<span style="color:#f92672">.&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span>create<span style="color:#f92672">()</span>
<span style="color:#f92672">.</span><span style="color:#a6e22e">before</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P2_NODE_ORDERING</span><span style="color:#f92672">)</span>
<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span>IntermediateProcessorStrategy<span style="color:#f92672">.</span><span style="color:#a6e22e">ROOT_PROC</span><span style="color:#f92672">)</span>
<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span>IntermediateProcessorStrategy<span style="color:#f92672">.</span><span style="color:#a6e22e">FAN_PROC</span><span style="color:#f92672">);</span>
</code></pre></div><p>It can be necessary to keep different configurations in our phase and assemble them depending on different graph features. <code>LayoutProcessorConfiguration</code> provides a way to do so, using the <code>addAll(...)</code> method:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> LayoutProcessorConfiguration<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> FOO_PROCESSING_ADDITIONS <span style="color:#f92672">=</span>
LayoutProcessorConfiguration<span style="color:#f92672">.&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span>create<span style="color:#f92672">()</span>
<span style="color:#f92672">.</span><span style="color:#a6e22e">addBefore</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P3_NODE_PLACEMENT</span><span style="color:#f92672">,</span> IntermediateProcessorStrategy<span style="color:#f92672">.</span><span style="color:#a6e22e">LEVEL_HEIGHT</span><span style="color:#f92672">)</span>
<span style="color:#f92672">.</span><span style="color:#a6e22e">addBefore</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P4_EDGE_ROUTING</span><span style="color:#f92672">,</span> IntermediateProcessorStrategy<span style="color:#f92672">.</span><span style="color:#a6e22e">NODE_POSITION_PROC</span><span style="color:#f92672">);</span>
<span style="color:#66d9ef">public</span> LayoutProcessorConfiguration<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">getLayoutProcessorConfiguration</span><span style="color:#f92672">(</span>ElkNode graph<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
<span style="color:#75715e">// Basic configuration
</span><span style="color:#75715e"></span> LayoutProcessorConfiguration<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> configuration <span style="color:#f92672">=</span>
LayoutProcessorConfiguration<span style="color:#f92672">.&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span>createFrom<span style="color:#f92672">(</span>
INTERMEDIATE_PROCESSING_CONFIG<span style="color:#f92672">);</span>
<span style="color:#75715e">// Additional dependencies
</span><span style="color:#75715e"></span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>foo<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
configuration<span style="color:#f92672">.</span><span style="color:#a6e22e">addAll</span><span style="color:#f92672">(</span>FOO_PROCESSING_ADDITIONS<span style="color:#f92672">);</span>
<span style="color:#f92672">}</span>
<span style="color:#66d9ef">return</span> configuration<span style="color:#f92672">;</span>
<span style="color:#f92672">}</span>
</code></pre></div><h3 id="assembling-the-algorithm">Assembling the Algorithm</h3>
<p>By now, we have phases, processors, a processor enumeration, and dependencies from phases to processors. What we do not have yet is a way to turn those configurations into a pipeline of layout processors that we can execute to compute a layout. What we are looking for is the <code>AlgorithmAssembler</code> class. But before we can use that, we need factories to create our layout phases.</p>
<p>Again, enumerations are a good way to implement those factories. For example:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> NodeOrderStrategy <span style="color:#66d9ef">implements</span> ILayoutPhaseFactory<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#f92672">{</span>
NODE_ORDERER<span style="color:#f92672">,</span>
ORDER_BALANCER<span style="color:#f92672">;</span>
<span style="color:#a6e22e">@Override</span>
<span style="color:#66d9ef">public</span> ILayoutPhase<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">create</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
<span style="color:#66d9ef">switch</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
<span style="color:#66d9ef">case</span> NODE_ORDERER<span style="color:#f92672">:</span>
<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> NodeOrderer<span style="color:#f92672">();</span>
<span style="color:#66d9ef">case</span> ORDER_BALANCER<span style="color:#f92672">:</span>
<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> OrderBalancer<span style="color:#f92672">();</span>
default:
<span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> IllegalArgumentException<span style="color:#f92672">(</span>
<span style="color:#e6db74">&#34;No implementation is available for the node orderer &#34;</span> <span style="color:#f92672">+</span> <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">toString</span><span style="color:#f92672">());</span>
<span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>Turning this into a separate enumeration allows this enumeration to be used as a layout option value for clients to specify which implementation they want.</p>
<p>We are now ready to assemble the whole algorithm, for example like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> LayoutProcessorConfiguration<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> OTHER_PROCESSORS <span style="color:#f92672">=</span>
LayoutProcessorConfiguration<span style="color:#f92672">.&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span>create<span style="color:#f92672">()</span>
<span style="color:#f92672">.</span><span style="color:#a6e22e">addAfter</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P4_EDGE_ROUTING</span><span style="color:#f92672">,</span> IntermediateProcessorStrategy<span style="color:#f92672">.</span><span style="color:#a6e22e">DETREEIFYING_PROC</span><span style="color:#f92672">);</span>
<span style="color:#66d9ef">private</span> <span style="color:#66d9ef">final</span> AlgorithmAssembler<span style="color:#f92672">&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span> algorithmAssembler <span style="color:#f92672">=</span>
AlgorithmAssembler<span style="color:#f92672">.&lt;</span>LayoutPhases<span style="color:#f92672">,</span> ElkNode<span style="color:#f92672">&gt;</span>create<span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">);</span>
<span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">layout</span><span style="color:#f92672">(</span>ElkNode graph<span style="color:#f92672">,</span> IElkProgressMonitor progressMonitor<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
List<span style="color:#f92672">&lt;</span>ILayoutProcessor<span style="color:#f92672">&lt;</span>ElkNode<span style="color:#f92672">&gt;&gt;</span> algorithm <span style="color:#f92672">=</span> assembleAlgorithm<span style="color:#f92672">(</span>graph<span style="color:#f92672">);</span>
progressMonitor<span style="color:#f92672">.</span><span style="color:#a6e22e">begin</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;Tree layout&#34;</span><span style="color:#f92672">,</span> algorithm<span style="color:#f92672">.</span><span style="color:#a6e22e">size</span><span style="color:#f92672">());</span>
<span style="color:#66d9ef">for</span> <span style="color:#f92672">(</span>ILayoutProcessor<span style="color:#f92672">&lt;</span>ElkNode<span style="color:#f92672">&gt;</span> processor <span style="color:#f92672">:</span> algorithm<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
processor<span style="color:#f92672">.</span><span style="color:#a6e22e">process</span><span style="color:#f92672">(</span>graph<span style="color:#f92672">,</span> progressMonitor<span style="color:#f92672">.</span><span style="color:#a6e22e">subTask</span><span style="color:#f92672">(</span>1<span style="color:#f92672">));</span>
<span style="color:#f92672">}</span>
progressMonitor<span style="color:#f92672">.</span><span style="color:#a6e22e">done</span><span style="color:#f92672">();</span>
<span style="color:#f92672">}</span>
<span style="color:#66d9ef">public</span> List<span style="color:#f92672">&lt;</span>ILayoutProcessor<span style="color:#f92672">&lt;</span>ElkNode<span style="color:#f92672">&gt;&gt;</span> <span style="color:#a6e22e">assembleAlgorithm</span><span style="color:#f92672">(</span>ElkNode graph<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
algorithmAssembler<span style="color:#f92672">.</span><span style="color:#a6e22e">reset</span><span style="color:#f92672">();</span>
<span style="color:#75715e">// Configure phases
</span><span style="color:#75715e"></span> algorithmAssembler<span style="color:#f92672">.</span><span style="color:#a6e22e">setPhase</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P1_TREEIFICATION</span><span style="color:#f92672">,</span>
graph<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">(</span>MrTreeOptions<span style="color:#f92672">.</span><span style="color:#a6e22e">TREEIFICATION_STRATEGY</span><span style="color:#f92672">));</span>
algorithmAssembler<span style="color:#f92672">.</span><span style="color:#a6e22e">setPhase</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P2_NODE_ORDERING</span><span style="color:#f92672">,</span>
graph<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">(</span>MrTreeOptions<span style="color:#f92672">.</span><span style="color:#a6e22e">NODE_ORDERING_STRATEGY</span><span style="color:#f92672">));</span>
algorithmAssembler<span style="color:#f92672">.</span><span style="color:#a6e22e">setPhase</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P3_NODE_PLACEMENT</span><span style="color:#f92672">,</span>
graph<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">(</span>MrTreeOptions<span style="color:#f92672">.</span><span style="color:#a6e22e">NODE_PLACEMENT_STRATEGY</span><span style="color:#f92672">));</span>
algorithmAssembler<span style="color:#f92672">.</span><span style="color:#a6e22e">setPhase</span><span style="color:#f92672">(</span>LayoutPhases<span style="color:#f92672">.</span><span style="color:#a6e22e">P4_EDGE_ROUTING</span><span style="color:#f92672">,</span>
graph<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">(</span>MrTreeOptions<span style="color:#f92672">.</span><span style="color:#a6e22e">EDGE_ROUTING_STRATEGY</span><span style="color:#f92672">));</span>
<span style="color:#75715e">// Some algorithms need to add custom processors, independent of
</span><span style="color:#75715e"></span> <span style="color:#75715e">// layout phases
</span><span style="color:#75715e"></span> algorithmAssembler<span style="color:#f92672">.</span><span style="color:#a6e22e">addProcessorConfiguration</span><span style="color:#f92672">(</span>OTHER_PROCESSORS<span style="color:#f92672">);</span>
<span style="color:#75715e">// Assemble the algorithm
</span><span style="color:#75715e"></span> <span style="color:#66d9ef">return</span> algorithmAssembler<span style="color:#f92672">.</span><span style="color:#a6e22e">build</span><span style="color:#f92672">(</span>graph<span style="color:#f92672">);</span>
<span style="color:#f92672">}</span>
</code></pre></div><h2 id="going-further">Going Further</h2>
<p>There are still some subtle points that we have left out so far. The following are a few pointers for things that are possible:</p>
<ul>
<li>The question of what should be a phase and what should be an intermediate processor is a somewhat philosophical one. A rough guideline is whether something is <em>always</em> part of the algorithm. If so, it might be a good candidate for a phase. As another rough guideline, ask yourself whether different implementations are possible for something. If so, it should probably be a phase.</li>
<li>The <code>AlgorithmAssembler</code> sorts intermediate processors in the same processing slot by the order in which they appear in the intermediate processor enumeration, but that can be changed. In fact, all you need to do is throw a custom <code>Comparator</code> at the <code>AlgorithmAssembler</code>. Your comparator might use other meta data available on the processors to sort them properly. The comparator only needs to be able to compare processors that will end up in the same processing slot.</li>
<li>It is possible for phases to be optional. While the <code>AlgorithmAssembler</code> usually throws an exception if the <code>build(...)</code> method is called while some phases are not yet configured, this behavior can be changed by calling <code>withFailOnMissingPhase(false)</code>.</li>
</ul>
</div>
<div class="secnav col-sm-3">
<ul>
<a href="../../../documentation/tooldevelopers.html">
<li class="navlevel-1">
Tool Developers
</li>
</a>
<a href="../../../documentation/tooldevelopers/graphdatastructure.html">
<li class="navlevel-2">
Graph Data Structure
</li>
</a>
<a href="../../../documentation/tooldevelopers/graphdatastructure/coordinatesystem.html">
<li class="navlevel-3">
Coordinate System
</li>
</a>
<a href="../../../documentation/tooldevelopers/graphdatastructure/layoutoptions.html">
<li class="navlevel-3">
Layout Options
</li>
</a>
<a href="../../../documentation/tooldevelopers/graphdatastructure/jsonformat.html">
<li class="navlevel-3">
JSON Format
</li>
</a>
<a href="../../../documentation/tooldevelopers/graphdatastructure/elktextformat.html">
<li class="navlevel-3">
ELK Text Format
</li>
</a>
<a href="../../../documentation/tooldevelopers/usingalgorithmsdirectly.html">
<li class="navlevel-2">
Using Algorithms Directly
</li>
</a>
<a href="../../../documentation/tooldevelopers/usingplainjavalayout.html">
<li class="navlevel-2">
Using Plain Java Layout
</li>
</a>
<a href="../../../documentation/tooldevelopers/usingeclipselayout.html">
<li class="navlevel-2">
Using Eclipse Layout
</li>
</a>
<a href="../../../documentation/tooldevelopers/usingeclipselayout/connectingtoelk.html">
<li class="navlevel-3">
Connecting to ELK
</li>
</a>
<a href="../../../documentation/tooldevelopers/usingeclipselayout/advancedconfiguration.html">
<li class="navlevel-3">
Advanced Configuration
</li>
</a>
<a href="../../../documentation/tooldevelopers/usingeclipselayout/layoutviewsupport.html">
<li class="navlevel-3">
Layout View Support
</li>
</a>
<a href="../../../documentation/tooldevelopers/usingeclipselayout/dependencyinjection.html">
<li class="navlevel-3">
Dependency Injection
</li>
</a>
<a href="../../../documentation/algorithmdevelopers.html">
<li class="navlevel-1">
Algorithm Developers
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/gettingeclipseready.html">
<li class="navlevel-2">
Getting Eclipse Ready
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/creatinganewproject.html">
<li class="navlevel-2">
Creating a New Project
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/metadatalanguage.html">
<li class="navlevel-2">
ELK Metadata Language
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/metadatalanguage/automaticbuilds.html">
<li class="navlevel-3">
Automatic Builds
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/algorithmimplementation.html">
<li class="navlevel-2">
Algorithm Implementation
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/algorithmimplementation/algorithmstructure.html">
<li class="navlevel-3 active">
Structuring Algorithms
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/algorithmdebugging.html">
<li class="navlevel-2">
Algorithm Debugging
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/randomgraphs.html">
<li class="navlevel-2">
Random Graph Generation
</li>
</a>
<a href="../../../documentation/algorithmdevelopers/unittesting.html">
<li class="navlevel-2">
Unit Tests
</li>
</a>
<a href="../../../documentation/contributors.html">
<li class="navlevel-1">
ELK Contributors
</li>
</a>
<a href="../../../documentation/contributors/developmentsetup.html">
<li class="navlevel-2">
Development Setup
</li>
</a>
<a href="../../../documentation/contributors/developmentworkflow.html">
<li class="navlevel-2">
Development Workflow
</li>
</a>
<a href="../../../documentation/contributors/developmentworkflow/installingwithoomph.html">
<li class="navlevel-3">
Installing With Oomph
</li>
</a>
<a href="../../../documentation/contributors/buildingelk.html">
<li class="navlevel-2">
Building ELK
</li>
</a>
</ul>
<div class="incubation-egg">
<a href="https://www.eclipse.org/projects/what-is-incubation.php">
<img src="https://www.eclipse.org/images/egg-incubation.png" alt="Incubation" />
</a>
</div>
</div>
</div>
</div>
<footer role="contentinfo" class="footer">
<div class="container">
<div class="row">
<div class="col">
<span class="hidden-print">
<a href="https://www.eclipse.org"><img class="logo-eclipse-white img-responsive" alt="logo" src="../../../img/eclipse_foundation_logo.svg"/></a>
</span>
</div>
<div class="col">
</div>
</div>
<div class="row">
<div class="col hidden-print">
<a href="http://www.eclipse.org/">Eclipse Foundation</a><br/>
<a href="http://www.eclipse.org/legal/privacy.php">Privacy Policy</a><br/>
<a href="http://www.eclipse.org/legal/termsofuse.php">Website Terms of Use</a><br/>
<a href="http://www.eclipse.org/legal/copyright.php">Copyright Agent</a><br/>
<a href="http://www.eclipse.org/legal">Legal</a>
</div>
<div class="col">
<p class="copyright-text">Copyright &copy; Eclipse Foundation, Inc. All Rights Reserved.</p>
</div>
</div>
</div>
</footer>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="https://www.eclipse.org/elk/js/prism.js"></script>
<script>$(function() { $('table').addClass('table'); })</script>
</body>
</html>