use of org.eclipse.elk.alg.force.graph.FGraph in project elk by eclipse.
the class ComponentsProcessor method recombine.
// ///////////////////////////////////////////////////////////////////////////////////////////
// Recombination
/**
* Pack the given components into a single graph.
*
* @param components a list of components.
* @return a single graph that contains all components.
*/
public FGraph recombine(final List<FGraph> components) {
if (components.size() == 1) {
return components.get(0);
} else if (components.size() <= 0) {
return new FGraph();
}
// assign priorities and sizes
for (FGraph graph : components) {
int priority = 0;
double minx = Integer.MAX_VALUE, miny = Integer.MAX_VALUE, maxx = Integer.MIN_VALUE, maxy = Integer.MIN_VALUE;
for (FNode node : graph.getNodes()) {
priority += node.getProperty(ForceOptions.PRIORITY);
// careful: the (x,y) of an FNode refers to its center
minx = Math.min(minx, node.getPosition().x - node.getSize().x / 2);
miny = Math.min(miny, node.getPosition().y - node.getSize().y / 2);
maxx = Math.max(maxx, node.getPosition().x + node.getSize().x / 2);
maxy = Math.max(maxy, node.getPosition().y + node.getSize().y / 2);
}
graph.setProperty(ForceOptions.PRIORITY, priority);
graph.setProperty(InternalProperties.BB_UPLEFT, new KVector(minx, miny));
graph.setProperty(InternalProperties.BB_LOWRIGHT, new KVector(maxx, maxy));
}
// sort the components by their priority and size
Collections.sort(components, new Comparator<FGraph>() {
public int compare(final FGraph graph1, final FGraph graph2) {
int prio = graph2.getProperty(ForceOptions.PRIORITY) - graph1.getProperty(ForceOptions.PRIORITY);
if (prio == 0) {
KVector size1 = graph1.getProperty(InternalProperties.BB_LOWRIGHT).clone().sub(graph1.getProperty(InternalProperties.BB_UPLEFT));
KVector size2 = graph2.getProperty(InternalProperties.BB_LOWRIGHT).clone().sub(graph2.getProperty(InternalProperties.BB_UPLEFT));
return Double.compare(size1.x * size1.y, size2.x * size2.y);
}
return prio;
}
});
FGraph result = new FGraph();
result.copyProperties(components.get(0));
// determine the maximal row width by the maximal box width and the total area
double maxRowWidth = 0.0f;
double totalArea = 0.0f;
for (FGraph graph : components) {
KVector size = graph.getProperty(InternalProperties.BB_LOWRIGHT).clone().sub(graph.getProperty(InternalProperties.BB_UPLEFT));
maxRowWidth = Math.max(maxRowWidth, size.x);
totalArea += size.x * size.y;
}
maxRowWidth = Math.max(maxRowWidth, (float) Math.sqrt(totalArea) * result.getProperty(ForceOptions.ASPECT_RATIO));
double spacing = result.getProperty(ForceOptions.SPACING_NODE_NODE).doubleValue();
// place nodes iteratively into rows
double xpos = 0, ypos = 0, highestBox = 0, broadestRow = spacing;
for (FGraph graph : components) {
KVector size = graph.getProperty(InternalProperties.BB_LOWRIGHT).clone().sub(graph.getProperty(InternalProperties.BB_UPLEFT));
if (xpos + size.x > maxRowWidth) {
// place the graph into the next row
xpos = 0;
ypos += highestBox + spacing;
highestBox = 0;
}
moveGraph(result, graph, xpos, ypos);
broadestRow = Math.max(broadestRow, xpos + size.x);
highestBox = Math.max(highestBox, size.y);
xpos += size.x + spacing;
}
return result;
}
use of org.eclipse.elk.alg.force.graph.FGraph in project elk by eclipse.
the class ComponentsProcessor method split.
// ///////////////////////////////////////////////////////////////////////////////////////////
// Splitting
/**
* Split the given graph into its connected components.
*
* @param graph an input graph.
* @return a list of components that can be processed one by one.
*/
public List<FGraph> split(final FGraph graph) {
Boolean separate = graph.getProperty(ForceOptions.SEPARATE_CONNECTED_COMPONENTS);
if (separate == null || separate.booleanValue()) {
boolean[] visited = new boolean[graph.getNodes().size()];
List<FEdge>[] incidence = buildIncidenceLists(graph);
// perform DFS starting on each node, collecting connected components
List<FGraph> components = new LinkedList<FGraph>();
for (FNode node : graph.getNodes()) {
FGraph comp = dfs(node, null, null, visited, incidence);
if (comp != null) {
comp.copyProperties(graph);
components.add(comp);
}
}
// redistribute identifier numbers to each component
if (components.size() > 1) {
for (FGraph comp : components) {
int id = 0;
for (FNode node : comp.getNodes()) {
node.id = id++;
}
}
}
return components;
}
return Lists.newArrayList(graph);
}
use of org.eclipse.elk.alg.force.graph.FGraph in project elk by eclipse.
the class ElkGraphImporter method importGraph.
// /////////////////////////////////////////////////////////////////////////////
// Transformation KGraph -> FGraph
@Override
public FGraph importGraph(final ElkNode kgraph) {
FGraph fgraph = new FGraph();
// copy the properties of the KGraph to the force graph
fgraph.copyProperties(kgraph);
// TODO Find another way to do this kind of bounds checking
// fgraph.checkProperties(Properties.SPACING, Properties.ASPECT_RATIO, Properties.TEMPERATURE,
// Properties.ITERATIONS, Properties.REPULSION);
fgraph.setProperty(InternalProperties.ORIGIN, kgraph);
// keep a list of created nodes in the force graph
Map<ElkNode, FNode> elemMap = new HashMap<ElkNode, FNode>();
// transform everything
transformNodes(kgraph, fgraph, elemMap);
transformEdges(kgraph, fgraph, elemMap);
return fgraph;
}
use of org.eclipse.elk.alg.force.graph.FGraph in project elk by eclipse.
the class StressLayoutProvider method layout.
@Override
public void layout(final ElkNode layoutGraph, final IElkProgressMonitor progressMonitor) {
progressMonitor.begin("ELK Stress", 1);
// calculate initial coordinates
if (!layoutGraph.getProperty(StressOptions.INTERACTIVE)) {
new ForceLayoutProvider().layout(layoutGraph, progressMonitor.subTask(1));
} else {
// Note that for the non-interactive case (above) this will be taken care of by the force layout provider
if (!layoutGraph.getProperty(StressOptions.OMIT_NODE_MICRO_LAYOUT)) {
NodeMicroLayout.forGraph(layoutGraph).execute();
}
}
// transform the input graph
IGraphImporter<ElkNode> graphImporter = new ElkGraphImporter();
FGraph fgraph = graphImporter.importGraph(layoutGraph);
// split the input graph into components
List<FGraph> components = componentsProcessor.split(fgraph);
// perform the actual layout
for (FGraph subGraph : components) {
if (subGraph.getNodes().size() <= 1) {
continue;
}
stressMajorization.initialize(subGraph);
stressMajorization.execute();
// Note that contrary to force itself, labels are not considered during stress layout.
// Hence, all we can do here is to place the labels at reasonable positions after layout has finished.
subGraph.getLabels().forEach(label -> label.refreshPosition());
}
// pack the components back into one graph
fgraph = componentsProcessor.recombine(components);
// apply the layout results to the original graph
graphImporter.applyLayout(fgraph);
progressMonitor.done();
}
Aggregations