use of org.eclipse.elk.core.util.Pair in project elk by eclipse.
the class HighDegreeNodeLayeringProcessor method process.
@Override
public void process(final LGraph graph, final IElkProgressMonitor progressMonitor) {
this.layeredGraph = graph;
// retrieve some properties
degreeThreshold = graph.getProperty(LayeredOptions.HIGH_DEGREE_NODES_THRESHOLD);
treeHeightThreshold = graph.getProperty(LayeredOptions.HIGH_DEGREE_NODES_TREE_HEIGHT);
// translate 0 to 'arbitrary height'
if (treeHeightThreshold == 0) {
treeHeightThreshold = Integer.MAX_VALUE;
}
// now iterate through all layer
final ListIterator<Layer> layerIt = graph.getLayers().listIterator();
while (layerIt.hasNext()) {
Layer lay = layerIt.next();
// -----------------------------------------------------------------------
// #1 find high degree nodes and find their incoming and outgoing trees
// -----------------------------------------------------------------------
List<Pair<LNode, HighDegreeNodeInformation>> highDegreeNodes = Lists.newArrayList();
int incMax = -1;
int outMax = -1;
for (LNode n : lay.getNodes()) {
if (isHighDegreeNode(n)) {
HighDegreeNodeInformation hdni = calculateInformation(n);
incMax = Math.max(incMax, hdni.incTreesMaxHeight);
outMax = Math.max(outMax, hdni.outTreesMaxHeight);
highDegreeNodes.add(Pair.of(n, hdni));
}
}
// -----------------------------------------------------------------------
// #2 insert layers before the current layer and move the trees
// -----------------------------------------------------------------------
List<Layer> preLayers = Lists.newArrayList();
for (int i = 0; i < incMax; ++i) {
preLayers.add(0, prependLayer(layerIt));
}
for (Pair<LNode, HighDegreeNodeInformation> highDegreeNode : highDegreeNodes) {
List<LNode> incRoots = highDegreeNode.getSecond().incTreeRoots;
if (incRoots == null) {
continue;
}
for (LNode incRoot : incRoots) {
moveTree(incRoot, INCOMING_EDGES, preLayers);
}
}
// -----------------------------------------------------------------------
// #2 insert layers after the current layer and move the trees
// -----------------------------------------------------------------------
List<Layer> afterLayers = Lists.newArrayList();
for (int i = 0; i < outMax; ++i) {
afterLayers.add(appendLayer(layerIt));
}
for (Pair<LNode, HighDegreeNodeInformation> highDegreeNode : highDegreeNodes) {
List<LNode> outRoots = highDegreeNode.getSecond().outTreeRoots;
if (outRoots == null) {
continue;
}
for (LNode outRoot : outRoots) {
moveTree(outRoot, OUTGOING_EDGES, afterLayers);
}
}
}
// -----------------------------------------------------------------------
// #2 it can happen that layers became empty
// after the previous processing, remove them
// -----------------------------------------------------------------------
ListIterator<Layer> layerIt2 = graph.getLayers().listIterator();
while (layerIt2.hasNext()) {
Layer l = layerIt2.next();
if (l.getNodes().isEmpty()) {
layerIt2.remove();
}
}
}
use of org.eclipse.elk.core.util.Pair in project elk by eclipse.
the class ElkGraphImporter method updateGraph.
@Override
public void updateGraph(final Graph g) {
Map<KVector, Pair<Node, ElkNode>> updatedNodeMap = Maps.newHashMap();
// reset graph
g.tEdges = null;
g.tree = null;
// update nodes
for (Node n : g.vertices) {
Pair<Node, ElkNode> original = nodeMap.get(n.originalVertex);
n.originalVertex = n.rect.getCenter();
updatedNodeMap.put(n.originalVertex, original);
}
nodeMap = updatedNodeMap;
}
use of org.eclipse.elk.core.util.Pair 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.util.Pair in project elk by eclipse.
the class DotExporter method parseSplinePoints.
/**
* Puts the points of a position string into a list of splines.
*
* @param posString string with spline points
* @param splines list of splines
* @param offset offset to add to coordinates
* @return the source and the target point, if specified by the position string
*/
private static Pair<KVector, KVector> parseSplinePoints(final String posString, final List<KVectorChain> splines, final KVector offset) {
KVector sourcePoint = null, targetPoint = null;
StringTokenizer splinesTokenizer = new StringTokenizer(posString, "\";");
while (splinesTokenizer.hasMoreTokens()) {
KVectorChain pointList = new KVectorChain();
StringTokenizer posTokenizer = new StringTokenizer(splinesTokenizer.nextToken(), " \t");
while (posTokenizer.hasMoreTokens()) {
String token = posTokenizer.nextToken();
try {
if (token.startsWith("s")) {
if (sourcePoint == null) {
sourcePoint = new KVector();
int commaIndex = token.indexOf(',');
sourcePoint.parse(token.substring(commaIndex + 1));
sourcePoint.add(offset);
}
} else if (token.startsWith("e")) {
if (targetPoint == null) {
targetPoint = new KVector();
int commaIndex = token.indexOf(',');
targetPoint.parse(token.substring(commaIndex + 1));
targetPoint.add(offset);
}
} else {
KVector point = new KVector();
point.parse(token);
pointList.add(point.add(offset));
}
} catch (IllegalArgumentException exception) {
// ignore exception
}
}
splines.add(pointList);
}
return new Pair<KVector, KVector>(sourcePoint, targetPoint);
}
use of org.eclipse.elk.core.util.Pair in project elk by eclipse.
the class DotImporter method transform.
/**
* Transform the GraphViz model into a KGraph.
*
* @param transData
* the transformation data instance that holds the source graph and is enriched with
* the new target graphs
*/
public void transform(final IDotTransformationData<GraphvizModel, ElkNode> transData) {
for (Graph graph : transData.getSourceGraph().getGraphs()) {
ElkNode parent = ElkGraphUtil.createGraph();
Map<String, ElkNode> nodeIdMap = Maps.newHashMap();
transData.setProperty(NODE_ID_MAP, nodeIdMap);
Map<Pair<ElkNode, String>, ElkPort> portIdMap = Maps.newHashMap();
transData.setProperty(PORT_ID_MAP, portIdMap);
transform(graph.getStatements(), parent, transData, new MapPropertyHolder(), new MapPropertyHolder());
transData.getTargetGraphs().add(parent);
parent.setProperty(PROP_GRAPH, graph);
}
}
Aggregations