org.jungrapht.visualization.layout.algorithms.sugiyama.VerticalAlignment Maven / Gradle / Ivy
The newest version!
package org.jungrapht.visualization.layout.algorithms.sugiyama;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.jgrapht.Graph;
import org.jgrapht.alg.util.NeighborCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @see "Fast and Simple Horizontal Coordinate Assignment, Ulrik Brandes and Boris Köpf, Department
* of Computer & Information Science, University of Konstanz"
* @param
* @param
*/
public abstract class VerticalAlignment {
private static final Logger log = LoggerFactory.getLogger(VerticalAlignment.class);
protected Map, LV> rootMap = new HashMap<>();
protected Map, LV> alignMap = new HashMap<>();
protected LV[][] layers;
protected Graph, LE> svGraph;
protected Set> markedSegments;
protected NeighborCache, LE> neighborCache;
public Map, LV> getRootMap() {
return rootMap;
}
public Map, LV> getAlignMap() {
return alignMap;
}
public abstract void align();
protected VerticalAlignment(
LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
this.layers = layers;
this.svGraph = svGraph;
this.neighborCache = new NeighborCache<>(svGraph);
this.markedSegments = markedSegments;
// initialize root and align
Arrays.stream(layers)
.flatMap(Arrays::stream)
.forEach(
v -> {
rootMap.put(v, v);
alignMap.put(v, v);
});
}
protected boolean notMarked(LE edge) {
return !markedSegments.contains(edge);
}
protected LV root(LV v) {
return rootMap.get(v);
}
protected void root(LV k, LV v) {
rootMap.put(k, v);
}
protected LV align(LV v) {
return alignMap.get(v);
}
protected void align(LV k, LV v) {
alignMap.put(k, v);
}
/**
* @param v vertix to get pos for
* @return the pos (index in rank) of the passed vertex
*/
protected int pos(LV v) {
return v.getIndex();
}
protected int alignMoveCursor(LV um, LV vkofi) {
align(um, vkofi);
root(vkofi, root(um));
align(vkofi, root(vkofi));
return pos(um);
}
/**
* start at first layer, work down, looking at predecessors
*
* @param
* @param
*/
public static class LeftmostUpper extends VerticalAlignment {
public LeftmostUpper(
LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
super(layers, svGraph, markedSegments);
}
@Override
public void align() {
for (int i = 0; i <= layers.length - 1; i++) {
int r = -1;
LV[] currentLayer = layers[i];
for (int k = 0; k <= currentLayer.length - 1; k++) {
LV vkofi = currentLayer[k];
List> neighbors =
neighborCache
.predecessorsOf(vkofi)
.stream()
.sorted(Comparator.comparingInt(LV::getIndex))
.collect(Collectors.toList());
int d = neighbors.size();
if (d > 0) {
int floor = (int) Math.floor((d - 1) / 2.0);
int ceil = (int) Math.ceil((d - 1) / 2.0);
for (int m : new int[] {floor, ceil}) {
if (align(vkofi) == vkofi) {
LV um = neighbors.get(m);
LE edge = svGraph.getEdge(um, vkofi);
if (notMarked(edge) && r < pos(um)) {
r = alignMoveCursor(um, vkofi);
}
}
if (floor == ceil) {
break;
}
}
}
}
}
}
}
public static class RightmostUpper extends VerticalAlignment {
// up right from top to bottom of layers, from left to right of rows
public RightmostUpper(
LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
super(layers, svGraph, markedSegments);
}
@Override
public void align() {
for (int i = 1; i <= layers.length - 1; i++) {
LV[] currentLayer = layers[i];
LV[] previousLayerInSweep = layers[i - 1];
int r =
previousLayerInSweep.length
+ 1; // one past the last index in the previous layer of this sweep
for (int k = currentLayer.length - 1; k >= 0; k--) {
LV vkofi = currentLayer[k];
List> neighbors =
neighborCache
.predecessorsOf(vkofi)
.stream()
.sorted(Comparator.comparingInt(LV::getIndex))
.collect(Collectors.toList());
int d = neighbors.size();
if (d > 0) {
int floor = (int) Math.floor((d - 1) / 2.0);
int ceil = (int) Math.ceil((d - 1) / 2.0);
for (int m : new int[] {ceil, floor}) {
if (align(vkofi) == vkofi) {
LV um = neighbors.get(m);
LE edge = svGraph.getEdge(um, vkofi);
if (notMarked(edge) && r > pos(um)) {
r = alignMoveCursor(um, vkofi);
}
}
if (floor == ceil) {
break;
}
}
}
}
}
}
}
/**
* start at last layer, work upwards looking at successor positions
*
* @param
* @param
*/
public static class LeftmostLower extends VerticalAlignment {
// down left from bottom to top of layers from left to right of rows
public LeftmostLower(
LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
super(layers, svGraph, markedSegments);
}
@Override
public void align() {
for (int i = layers.length - 2; i >= 0; i--) {
int r = -1; // one before the first index of the previous layer of this sweep
LV[] currentLayer = layers[i];
for (int k = 0; k < currentLayer.length; k++) {
LV vkofi = currentLayer[k];
List> neighbors =
neighborCache
.successorsOf(vkofi)
.stream()
.sorted(Comparator.comparingInt(LV::getIndex))
.collect(Collectors.toList());
int d = neighbors.size();
if (d > 0) {
int floor = (int) Math.floor((d - 1) / 2.0);
int ceil = (int) Math.ceil((d - 1) / 2.0);
for (int m : new int[] {floor, ceil}) {
if (align(vkofi) == vkofi) {
LV um = neighbors.get(m);
LE edge = svGraph.getEdge(vkofi, um);
if (notMarked(edge) && r < pos(um)) {
r = alignMoveCursor(um, vkofi);
}
}
if (floor == ceil) {
break;
}
}
}
}
}
}
}
/**
* start at last layer, work up, looking at successors
*
* @param
* @param
*/
public static class RightmostLower extends VerticalAlignment {
// down right from bottom to top of layers from right to left
public RightmostLower(
LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
super(layers, svGraph, markedSegments);
}
@Override
public void align() {
for (int i = layers.length - 2; i >= 0; i--) {
LV[] currentLayer = layers[i];
LV[] previousLayerInSweep = layers[i + 1];
int r =
previousLayerInSweep.length
+ 1; // one past the last index in the previous layer of this sweep
for (int k = currentLayer.length - 1; k >= 0; k--) {
LV vkofi = currentLayer[k];
List> neighbors =
neighborCache
.successorsOf(vkofi)
.stream()
.sorted(Comparator.comparingInt(LV::getIndex))
.collect(Collectors.toList());
int d = neighbors.size();
if (d > 0) {
int floor = (int) Math.floor((d - 1) / 2.0);
int ceil = (int) Math.ceil((d - 1) / 2.0);
for (int m : new int[] {ceil, floor}) {
if (align(vkofi) == vkofi) {
LV um = neighbors.get(m);
LE edge = svGraph.getEdge(vkofi, um);
if (notMarked(edge) && r > pos(um)) {
r = alignMoveCursor(um, vkofi);
}
}
if (floor == ceil) {
break;
}
}
}
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy