use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class LinearSegmentsNodePlacer method postProcess.
// /////////////////////////////////////////////////////////////////////////////
// Post Processing for Correction
/**
* Post-process the balanced placement by moving linear segments where obvious improvements can
* be made.
*
* @param layeredGraph
* the layered graph
*/
private void postProcess(final LGraph layeredGraph) {
// process each linear segment independently
for (LinearSegment segment : linearSegments) {
double minRoomAbove = Integer.MAX_VALUE, minRoomBelow = Integer.MAX_VALUE;
for (LNode node : segment.nodes) {
double roomAbove, roomBelow;
int index = node.getIndex();
// determine the amount by which the linear segment can be moved up without overlap
if (index > 0) {
LNode neighbor = node.getLayer().getNodes().get(index - 1);
double spacing = spacings.getVerticalSpacing(node, neighbor);
roomAbove = node.getPosition().y - node.getMargin().top - (neighbor.getPosition().y + neighbor.getSize().y + neighbor.getMargin().bottom + spacing);
} else {
roomAbove = node.getPosition().y - node.getMargin().top;
}
minRoomAbove = Math.min(roomAbove, minRoomAbove);
// overlap
if (index < node.getLayer().getNodes().size() - 1) {
LNode neighbor = node.getLayer().getNodes().get(index + 1);
double spacing = spacings.getVerticalSpacing(node, neighbor);
roomBelow = neighbor.getPosition().y - neighbor.getMargin().top - (node.getPosition().y + node.getSize().y + node.getMargin().bottom + spacing);
} else {
roomBelow = 2 * node.getPosition().y;
}
minRoomBelow = Math.min(roomBelow, minRoomBelow);
}
double minDisplacement = Integer.MAX_VALUE;
boolean foundPlace = false;
// determine the minimal displacement that would make one incoming edge straight
LNode firstNode = segment.nodes.get(0);
for (LPort target : firstNode.getPorts()) {
double pos = firstNode.getPosition().y + target.getPosition().y + target.getAnchor().y;
for (LEdge edge : target.getIncomingEdges()) {
LPort source = edge.getSource();
double d = source.getNode().getPosition().y + source.getPosition().y + source.getAnchor().y - pos;
if (Math.abs(d) < Math.abs(minDisplacement) && Math.abs(d) < (d < 0 ? minRoomAbove : minRoomBelow)) {
minDisplacement = d;
foundPlace = true;
}
}
}
// determine the minimal displacement that would make one outgoing edge straight
LNode lastNode = segment.nodes.get(segment.nodes.size() - 1);
for (LPort source : lastNode.getPorts()) {
double pos = lastNode.getPosition().y + source.getPosition().y + source.getAnchor().y;
for (LEdge edge : source.getOutgoingEdges()) {
LPort target = edge.getTarget();
double d = target.getNode().getPosition().y + target.getPosition().y + target.getAnchor().y - pos;
if (Math.abs(d) < Math.abs(minDisplacement) && Math.abs(d) < (d < 0 ? minRoomAbove : minRoomBelow)) {
minDisplacement = d;
foundPlace = true;
}
}
}
// if such a displacement could be found, apply it to the whole linear segment
if (foundPlace && minDisplacement != 0) {
for (LNode node : segment.nodes) {
node.getPosition().y += minDisplacement;
}
}
}
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class LinearSegmentsNodePlacer method sortLinearSegments.
// /////////////////////////////////////////////////////////////////////////////
// Linear Segments Creation
/**
* Sorts the linear segments of the given layered graph by finding a topological ordering in the
* corresponding segment ordering graph.
*
* @param layeredGraph
* layered graph to process
* @param monitor
* our progress monitor.
* @return a sorted array of linear segments
*/
private LinearSegment[] sortLinearSegments(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
// set the identifier and input / output priority for all nodes
List<LinearSegment> segmentList = Lists.newArrayList();
for (Layer layer : layeredGraph) {
for (LNode node : layer) {
node.id = -1;
int inprio = Integer.MIN_VALUE, outprio = Integer.MIN_VALUE;
for (LPort port : node.getPorts()) {
for (LEdge edge : port.getIncomingEdges()) {
int prio = edge.getProperty(LayeredOptions.PRIORITY_STRAIGHTNESS);
inprio = Math.max(inprio, prio);
}
for (LEdge edge : port.getOutgoingEdges()) {
int prio = edge.getProperty(LayeredOptions.PRIORITY_STRAIGHTNESS);
outprio = Math.max(outprio, prio);
}
}
node.setProperty(INPUT_PRIO, inprio);
node.setProperty(OUTPUT_PRIO, outprio);
}
}
// create linear segments for the layered graph, ignoring odd port side dummies
int nextLinearSegmentID = 0;
for (Layer layer : layeredGraph) {
for (LNode node : layer) {
// to be != -1.
if (node.id < 0) {
LinearSegment segment = new LinearSegment();
segment.id = nextLinearSegmentID++;
fillSegment(node, segment);
segmentList.add(segment);
}
}
}
// create and initialize segment ordering graph
List<List<LinearSegment>> outgoingList = Lists.newArrayListWithCapacity(segmentList.size());
List<Integer> incomingCountList = Lists.newArrayListWithCapacity(segmentList.size());
for (int i = 0; i < segmentList.size(); i++) {
outgoingList.add(new ArrayList<LinearSegment>());
incomingCountList.add(0);
}
// create edges for the segment ordering graph
createDependencyGraphEdges(monitor, layeredGraph, segmentList, outgoingList, incomingCountList);
// turn lists into arrays
LinearSegment[] segments = segmentList.toArray(new LinearSegment[segmentList.size()]);
@SuppressWarnings("unchecked") List<LinearSegment>[] outgoing = outgoingList.toArray(new List[outgoingList.size()]);
int[] incomingCount = new int[incomingCountList.size()];
for (int i = 0; i < incomingCount.length; i++) {
incomingCount[i] = incomingCountList.get(i);
}
// gather the sources of the segment ordering graph
int nextRank = 0;
List<LinearSegment> noIncoming = Lists.newArrayList();
for (int i = 0; i < segments.length; i++) {
if (incomingCount[i] == 0) {
noIncoming.add(segments[i]);
}
}
// find a topological ordering of the segment ordering graph
int[] newRanks = new int[segments.length];
while (!noIncoming.isEmpty()) {
LinearSegment segment = noIncoming.remove(0);
newRanks[segment.id] = nextRank++;
while (!outgoing[segment.id].isEmpty()) {
LinearSegment target = outgoing[segment.id].remove(0);
incomingCount[target.id]--;
if (incomingCount[target.id] == 0) {
noIncoming.add(target);
}
}
}
// apply the new ordering to the array of linear segments
linearSegments = new LinearSegment[segments.length];
for (int i = 0; i < segments.length; i++) {
assert outgoing[i].isEmpty();
LinearSegment ls = segments[i];
int rank = newRanks[i];
linearSegments[rank] = ls;
ls.id = rank;
for (LNode node : ls.nodes) {
node.id = rank;
}
}
return linearSegments;
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class CrossingsCounter method countCrossingsOnPorts.
private int countCrossingsOnPorts(final Iterable<LPort> ports) {
int crossings = 0;
for (LPort port : ports) {
indexTree.removeAll(positionOf(port));
// First get crossings for all edges.
for (LEdge edge : port.getConnectedEdges()) {
int endPosition = positionOf(otherEndOf(edge, port));
if (endPosition > positionOf(port)) {
crossings += indexTree.rank(endPosition);
ends.push(endPosition);
}
}
// Then add end points.
while (!ends.isEmpty()) {
indexTree.add(ends.pop());
}
}
return crossings;
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class CrossingsCounter method countInLayerCrossingsOnPorts.
private int countInLayerCrossingsOnPorts(final Iterable<LPort> ports) {
int crossings = 0;
for (LPort port : ports) {
indexTree.removeAll(positionOf(port));
int numBetweenLayerEdges = 0;
// First get crossings for all edges.
for (LEdge edge : port.getConnectedEdges()) {
if (isInLayer(edge)) {
int endPosition = positionOf(otherEndOf(edge, port));
if (endPosition > positionOf(port)) {
crossings += indexTree.rank(endPosition);
ends.push(endPosition);
}
} else {
numBetweenLayerEdges++;
}
}
crossings += indexTree.size() * numBetweenLayerEdges;
// Then add end points.
while (!ends.isEmpty()) {
indexTree.add(ends.pop());
}
}
return crossings;
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class HyperedgeCrossingsCounter method countCrossings.
/**
* Special crossings counting method for hyperedges. See
* <ul>
* <li>M. Spönemann, C. D. Schulze, U. Rüegg, R. von Hanxleden.
* Counting crossings for layered hypergraphs, In <i>DIAGRAMS 2014</i>,
* volume 8578 of LNAI, Springer, 2014.</li>
* </ul>
*
* @param leftLayer
* the left layer
* @param rightLayer
* the right layer
* @return the number of edge crossings
*/
// SUPPRESS CHECKSTYLE NEXT 1 MethodLength
public int countCrossings(final LNode[] leftLayer, final LNode[] rightLayer) {
// Assign index values to the ports of the left layer
int sourceCount = 0;
for (LNode node : leftLayer) {
// Assign index values in the order north - east - south - west
for (LPort port : node.getPorts()) {
int portEdges = 0;
for (LEdge edge : port.getOutgoingEdges()) {
if (node.getLayer() != edge.getTarget().getNode().getLayer()) {
portEdges++;
}
}
if (portEdges > 0) {
portPos[port.id] = sourceCount++;
}
}
}
// Assign index values to the ports of the right layer
int targetCount = 0;
for (LNode node : rightLayer) {
// Determine how many input ports there are on the north side
// (note that the standard port order is north - east - south - west)
int northInputPorts = 0;
for (LPort port : node.getPorts()) {
if (port.getSide() == PortSide.NORTH) {
for (LEdge edge : port.getIncomingEdges()) {
if (node.getLayer() != edge.getSource().getNode().getLayer()) {
northInputPorts++;
break;
}
}
} else {
break;
}
}
// Assign index values in the order north - west - south - east
int otherInputPorts = 0;
ListIterator<LPort> portIter = node.getPorts().listIterator(node.getPorts().size());
while (portIter.hasPrevious()) {
LPort port = portIter.previous();
int portEdges = 0;
for (LEdge edge : port.getIncomingEdges()) {
if (node.getLayer() != edge.getSource().getNode().getLayer()) {
portEdges++;
}
}
if (portEdges > 0) {
if (port.getSide() == PortSide.NORTH) {
portPos[port.id] = targetCount;
targetCount++;
} else {
portPos[port.id] = targetCount + northInputPorts + otherInputPorts;
otherInputPorts++;
}
}
}
targetCount += otherInputPorts;
}
// Gather hyperedges
Map<LPort, Hyperedge> port2HyperedgeMap = Maps.newHashMap();
Set<Hyperedge> hyperedgeSet = Sets.newLinkedHashSet();
for (LNode node : leftLayer) {
for (LPort sourcePort : node.getPorts()) {
for (LEdge edge : sourcePort.getOutgoingEdges()) {
LPort targetPort = edge.getTarget();
if (node.getLayer() != targetPort.getNode().getLayer()) {
Hyperedge sourceHE = port2HyperedgeMap.get(sourcePort);
Hyperedge targetHE = port2HyperedgeMap.get(targetPort);
if (sourceHE == null && targetHE == null) {
Hyperedge hyperedge = new Hyperedge();
hyperedgeSet.add(hyperedge);
hyperedge.edges.add(edge);
hyperedge.ports.add(sourcePort);
port2HyperedgeMap.put(sourcePort, hyperedge);
hyperedge.ports.add(targetPort);
port2HyperedgeMap.put(targetPort, hyperedge);
} else if (sourceHE == null) {
targetHE.edges.add(edge);
targetHE.ports.add(sourcePort);
port2HyperedgeMap.put(sourcePort, targetHE);
} else if (targetHE == null) {
sourceHE.edges.add(edge);
sourceHE.ports.add(targetPort);
port2HyperedgeMap.put(targetPort, sourceHE);
} else if (sourceHE == targetHE) {
sourceHE.edges.add(edge);
} else {
sourceHE.edges.add(edge);
for (LPort p : targetHE.ports) {
port2HyperedgeMap.put(p, sourceHE);
}
sourceHE.edges.addAll(targetHE.edges);
sourceHE.ports.addAll(targetHE.ports);
hyperedgeSet.remove(targetHE);
}
}
}
}
}
// Determine top and bottom positions for each hyperedge
Hyperedge[] hyperedges = hyperedgeSet.toArray(new Hyperedge[hyperedgeSet.size()]);
Layer leftLayerRef = leftLayer[0].getLayer();
Layer rightLayerRef = rightLayer[0].getLayer();
for (Hyperedge he : hyperedges) {
he.upperLeft = sourceCount;
he.upperRight = targetCount;
for (LPort port : he.ports) {
int pos = portPos[port.id];
if (port.getNode().getLayer() == leftLayerRef) {
if (pos < he.upperLeft) {
he.upperLeft = pos;
}
if (pos > he.lowerLeft) {
he.lowerLeft = pos;
}
} else if (port.getNode().getLayer() == rightLayerRef) {
if (pos < he.upperRight) {
he.upperRight = pos;
}
if (pos > he.lowerRight) {
he.lowerRight = pos;
}
}
}
}
// Determine the sequence of edge target positions sorted by source and target index
Arrays.sort(hyperedges);
int[] southSequence = new int[hyperedges.length];
int[] compressDeltas = new int[targetCount + 1];
for (int i = 0; i < hyperedges.length; i++) {
southSequence[i] = hyperedges[i].upperRight;
compressDeltas[southSequence[i]] = 1;
}
int delta = 0;
for (int i = 0; i < compressDeltas.length; i++) {
if (compressDeltas[i] == 1) {
compressDeltas[i] = delta;
} else {
delta--;
}
}
int q = 0;
for (int i = 0; i < southSequence.length; i++) {
southSequence[i] += compressDeltas[southSequence[i]];
q = Math.max(q, southSequence[i] + 1);
}
// Build the accumulator tree
int firstIndex = 1;
while (firstIndex < q) {
firstIndex *= 2;
}
int treeSize = 2 * firstIndex - 1;
firstIndex -= 1;
int[] tree = new int[treeSize];
// Count the straight-line crossings of the topmost edges
int crossings = 0;
for (int k = 0; k < southSequence.length; k++) {
int index = southSequence[k] + firstIndex;
tree[index]++;
while (index > 0) {
if (index % 2 > 0) {
crossings += tree[index + 1];
}
index = (index - 1) / 2;
tree[index]++;
}
}
// Create corners for the left side
HyperedgeCorner[] leftCorners = new HyperedgeCorner[hyperedges.length * 2];
for (int i = 0; i < hyperedges.length; i++) {
leftCorners[2 * i] = new HyperedgeCorner(hyperedges[i], hyperedges[i].upperLeft, hyperedges[i].lowerLeft, HyperedgeCorner.Type.UPPER);
leftCorners[2 * i + 1] = new HyperedgeCorner(hyperedges[i], hyperedges[i].lowerLeft, hyperedges[i].upperLeft, HyperedgeCorner.Type.LOWER);
}
Arrays.sort(leftCorners);
// Count crossings caused by overlapping hyperedge areas on the left side
int openHyperedges = 0;
for (int i = 0; i < leftCorners.length; i++) {
switch(leftCorners[i].type) {
case UPPER:
openHyperedges++;
break;
case LOWER:
openHyperedges--;
crossings += openHyperedges;
break;
}
}
// Create corners for the right side
HyperedgeCorner[] rightCorners = new HyperedgeCorner[hyperedges.length * 2];
for (int i = 0; i < hyperedges.length; i++) {
rightCorners[2 * i] = new HyperedgeCorner(hyperedges[i], hyperedges[i].upperRight, hyperedges[i].lowerRight, HyperedgeCorner.Type.UPPER);
rightCorners[2 * i + 1] = new HyperedgeCorner(hyperedges[i], hyperedges[i].lowerRight, hyperedges[i].upperRight, HyperedgeCorner.Type.LOWER);
}
Arrays.sort(rightCorners);
// Count crossings caused by overlapping hyperedge areas on the right side
openHyperedges = 0;
for (int i = 0; i < rightCorners.length; i++) {
switch(rightCorners[i].type) {
case UPPER:
openHyperedges++;
break;
case LOWER:
openHyperedges--;
crossings += openHyperedges;
break;
}
}
return crossings;
}
Aggregations