use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopHolder in project elk by eclipse.
the class SelfLoopPostProcessor method processNode.
private void processNode(final LNode lNode) {
SelfLoopHolder slHolder = lNode.getProperty(InternalProperties.SELF_LOOP_HOLDER);
slHolder.getSLHyperLoops().stream().flatMap(slLoop -> slLoop.getSLEdges().stream()).forEach(slEdge -> restoreEdge(lNode, slEdge));
slHolder.getSLHyperLoops().stream().filter(slLoop -> slLoop.getSLLabels() != null).forEach(slLoop -> slLoop.getSLLabels().applyPlacement(lNode.getPosition()));
}
use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopHolder in project elk by eclipse.
the class SelfLoopPreProcessor method process.
@Override
public void process(final LGraph graph, final IElkProgressMonitor progressMonitor) {
progressMonitor.begin("Self-Loop pre-processing", 1);
for (LNode lnode : graph.getLayerlessNodes()) {
if (SelfLoopHolder.needsSelfLoopProcessing(lnode)) {
SelfLoopHolder slHolder = SelfLoopHolder.install(lnode);
hideSelfLoops(slHolder);
hidePorts(slHolder);
}
}
progressMonitor.done();
}
use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopHolder in project elk by eclipse.
the class RoutingDirector method determineFourSideLoopRoutes.
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Route Determination (Four Sides)
/**
* For four-sided self loops, we have at least one port on every side. If we look at the list of ports, this means
* that we want to insert a break between some pair of ports adjacent in that list: one will become the leftmost
* port, and the other will become the rightmost port. What we want to do is find the pair of ports with the maximum
* number of ports with external connections between them, since that will minimize the number of edge crossings our
* routing will produce.
*/
private void determineFourSideLoopRoutes(final SelfHyperLoop slLoop) {
// The self loop ports are sorted by ID
List<SelfLoopPort> sortedSLPorts = slLoop.getSLPorts();
SelfLoopHolder slHolder = slLoop.getSLHolder();
// Go through each pair of adjacent ports and find the one which incurs the highest penalty if we drew an edge
// between them. That's the pair we want to split the loop at. We start with the uppermost port on the western
// side and the leftmost on the northern side and then compare successive pairs against those two
SelfLoopPort worstLeftPort = sortedSLPorts.get(sortedSLPorts.size() - 1);
SelfLoopPort worstRightPort = sortedSLPorts.get(0);
int worstPenalty = computeEdgePenalty(slHolder, worstLeftPort, worstRightPort);
for (int rightPortIndex = 1; rightPortIndex < sortedSLPorts.size(); rightPortIndex++) {
SelfLoopPort currLeftPort = sortedSLPorts.get(rightPortIndex - 1);
SelfLoopPort currRightPort = sortedSLPorts.get(rightPortIndex);
int currPenalty = computeEdgePenalty(slHolder, currLeftPort, currRightPort);
if (currPenalty > worstPenalty) {
worstLeftPort = currLeftPort;
worstRightPort = currRightPort;
worstPenalty = currPenalty;
}
}
// Since we _don't_ want to draw the self loop between the left and right ports, we switch them here
slLoop.setLeftmostPort(worstRightPort);
slLoop.setRightmostPort(worstLeftPort);
}
use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopHolder in project elk by eclipse.
the class RoutingSlotAssigner method shiftTowardsNodeOnSide.
private void shiftTowardsNodeOnSide(final SelfLoopHolder slHolder, final PortSide side, final int[] nextFreeRoutingSlotAtPort, final boolean[][] labelCrossingMatrix) {
// We will iterate over the self loops that occupy that port side, sorted ascendingly by routing slot
List<SelfHyperLoop> slLoops = slHolder.getSLHyperLoops().stream().filter(slLoop -> slLoop.getOccupiedPortSides().contains(side)).sorted((sl1, sl2) -> Integer.compare(sl1.getRoutingSlot(side), sl2.getRoutingSlot(side))).collect(Collectors.toList());
// Find the indices of the first and last regular port on the port side
int minLPortIndex = Integer.MAX_VALUE;
int maxLPortIndex = Integer.MIN_VALUE;
for (LPort lPort : slHolder.getLNode().getPorts()) {
if (lPort.getSide() == side) {
minLPortIndex = Math.min(minLPortIndex, lPort.id);
maxLPortIndex = Math.max(maxLPortIndex, lPort.id);
}
}
if (minLPortIndex == Integer.MAX_VALUE) {
// won't cause label overlaps.
for (int i = 0; i < slLoops.size(); i++) {
slLoops.get(i).setRoutingSlot(side, i);
}
} else {
int[] slotAssignedToLabel = new int[labelCrossingMatrix.length];
Arrays.fill(slotAssignedToLabel, -1);
// no label our loop label conflicts with is assigned to that slot
for (SelfHyperLoop slLoop : slLoops) {
boolean[] activeAtPort = slLoopActivityOverPorts.get(slLoop);
int lowestAvailableSlot = 0;
for (int portIndex = minLPortIndex; portIndex <= maxLPortIndex; portIndex++) {
if (activeAtPort[portIndex]) {
lowestAvailableSlot = Math.max(lowestAvailableSlot, nextFreeRoutingSlotAtPort[portIndex]);
}
}
// conflict-free slot
if (slLoop.getSLLabels() != null) {
int ourLabelIdx = slLoop.getSLLabels().id;
Set<Integer> slotsWithLabelConflicts = new HashSet<>();
for (int otherLabelIdx = 0; otherLabelIdx < labelCrossingMatrix.length; otherLabelIdx++) {
if (labelCrossingMatrix[ourLabelIdx][otherLabelIdx]) {
slotsWithLabelConflicts.add(slotAssignedToLabel[otherLabelIdx]);
}
}
// Find the first slot (starting with out lowest available) that does not appear in the set
while (slotsWithLabelConflicts.contains(lowestAvailableSlot)) {
lowestAvailableSlot++;
}
}
// Assign the loop to that routing slot and update out routing slot array
slLoop.setRoutingSlot(side, lowestAvailableSlot);
for (int portIndex = minLPortIndex; portIndex <= maxLPortIndex; portIndex++) {
if (activeAtPort[portIndex]) {
nextFreeRoutingSlotAtPort[portIndex] = lowestAvailableSlot + 1;
}
}
// If we have a label, update the label's routing slot
if (slLoop.getSLLabels() != null) {
slotAssignedToLabel[slLoop.getSLLabels().id] = lowestAvailableSlot;
}
}
}
}
use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopHolder in project elk by eclipse.
the class PortRestorer method restorePorts.
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Port Restoring
private void restorePorts(final SelfLoopHolder slHolder) {
// We're building up a new port list and replace the old one once we're finished. That's more efficient than
// continually inserting ports into the middle of the existing list.
LNode lNode = slHolder.getLNode();
// We'll add the old ports in bursts and always remember where the next burst starts
List<LPort> oldPortList = new ArrayList<>(lNode.getPorts());
int nextOldPortIndex = 0;
List<LPort> newPortList = lNode.getPorts();
newPortList.clear();
// Go over the target areas and add them in between the regular ports
addAll(targetAreas.get(PortSide.NORTH, PortSideArea.START), lNode);
nextOldPortIndex = addAllThat(oldPortList, nextOldPortIndex, (lPort) -> lPort.getSide() == PortSide.NORTH && isNorthSouthPortWithWestOrWestEastConnections(lPort), newPortList);
addAll(targetAreas.get(PortSide.NORTH, PortSideArea.MIDDLE), lNode);
nextOldPortIndex = addAllThat(oldPortList, nextOldPortIndex, (lPort) -> lPort.getSide() == PortSide.NORTH, newPortList);
addAll(targetAreas.get(PortSide.NORTH, PortSideArea.END), lNode);
addAll(targetAreas.get(PortSide.EAST, PortSideArea.START), lNode);
addAll(targetAreas.get(PortSide.EAST, PortSideArea.MIDDLE), lNode);
nextOldPortIndex = addAllThat(oldPortList, nextOldPortIndex, (lPort) -> lPort.getSide() == PortSide.EAST, newPortList);
addAll(targetAreas.get(PortSide.EAST, PortSideArea.END), lNode);
addAll(targetAreas.get(PortSide.SOUTH, PortSideArea.START), lNode);
nextOldPortIndex = addAllThat(oldPortList, nextOldPortIndex, (lPort) -> lPort.getSide() == PortSide.SOUTH && isNorthSouthPortWithEastConnections(lPort), newPortList);
addAll(targetAreas.get(PortSide.SOUTH, PortSideArea.MIDDLE), lNode);
nextOldPortIndex = addAllThat(oldPortList, nextOldPortIndex, (lPort) -> lPort.getSide() == PortSide.SOUTH, newPortList);
addAll(targetAreas.get(PortSide.SOUTH, PortSideArea.END), lNode);
addAll(targetAreas.get(PortSide.WEST, PortSideArea.START), lNode);
nextOldPortIndex = addAllThat(oldPortList, nextOldPortIndex, (lPort) -> lPort.getSide() == PortSide.WEST, newPortList);
addAll(targetAreas.get(PortSide.WEST, PortSideArea.MIDDLE), lNode);
addAll(targetAreas.get(PortSide.WEST, PortSideArea.END), lNode);
assert newPortList.size() >= oldPortList.size() && newPortList.size() >= slHolder.getSLPortMap().size();
assert !slHolder.arePortsHidden() || newPortList.size() > oldPortList.size();
}
Aggregations