use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort in project elk by eclipse.
the class SelfLoopPreProcessor method hidePorts.
/**
* Possibly hides all ports whose only incident edges are self loops. This is only done if port constraints are not
* at least {@link PortConstraints#FIXED_ORDER}.
*/
private void hidePorts(final SelfLoopHolder slHolder) {
LNode lNode = slHolder.getLNode();
LGraph nestedGraph = lNode.getNestedGraph();
/* There are two cases in which we want to refrain from hiding ports:
* 1. The port order is already fixed. Then the code that would compute a proper port order won't be confused by
* the self-loop ports, so there's no need to hide them.
* 2. The self loop holder has another graph inside of it which contains external ports. In that case, the
* crossing minimization will compute proper port orders. The self loop holder will have the port order
* applied and its port constraints set to FIXED_POS, so this is basically the first case with extra steps.
*/
boolean orderFixed = lNode.getProperty(LayeredOptions.PORT_CONSTRAINTS).isOrderFixed();
boolean hierarchyMode = nestedGraph != null && nestedGraph.getProperty(InternalProperties.GRAPH_PROPERTIES).contains(GraphProperties.EXTERNAL_PORTS);
if (orderFixed || hierarchyMode) {
// No need to hide any ports
return;
}
for (SelfLoopPort slPort : slHolder.getSLPortMap().values()) {
if (slPort.hadOnlySelfLoops()) {
// Hide the port
LPort lPort = slPort.getLPort();
lPort.setNode(null);
// Remember that we actually did so
slPort.setHidden(true);
slHolder.setPortsHidden(true);
// run into this case.
assert lPort.getProperty(InternalProperties.PORT_DUMMY) == null;
}
}
}
use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort 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.SelfLoopPort in project elk by eclipse.
the class PortSideAssigner method assignToTarget.
/**
* Assigns the given self loop to the given target.
*/
private void assignToTarget(final SelfHyperLoop slLoop, final Target target) {
// Gather the self loop's ports
List<SelfLoopPort> slPorts = slLoop.getSLPorts();
// same side anyway, so there's no need for us to sort anything
if (target.isCornerTarget()) {
// This will sort the port's original list, but that's okay since it doesn't have any particular order
// prior to running the PortRestorer
slPorts.sort((slPort1, slPort2) -> Integer.compare(slPort1.getLPort().getNetFlow(), slPort2.getLPort().getNetFlow()));
}
// Assign the first half of the ports to the first side, and the second half to the second side. However, only
// assign ports that have been hidden and can thus be freely assigned to a side. This could be done way more
// intelligently, but hopefully bad cases won't be common enough to warrant more effort here.
int secondHalfStartIndex = slPorts.size() / 2;
for (int i = 0; i < secondHalfStartIndex; i++) {
SelfLoopPort slPort = slPorts.get(i);
if (slPort.isHidden()) {
slPort.getLPort().setSide(target.firstSide);
}
}
for (int i = secondHalfStartIndex; i < slPorts.size(); i++) {
SelfLoopPort slPort = slPorts.get(i);
if (slPort.isHidden()) {
slPort.getLPort().setSide(target.secondSide);
}
}
}
use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort in project elk by eclipse.
the class LabelPlacer method computeCoordinates.
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Coordinate Computation
private void computeCoordinates(final SelfHyperLoop slLoop) {
// The coordinates really only depend on the alignment since LEFT, CENTER and RIGHT are specific to the north
// and south sides while TOP is specific to the east and west sides
SelfHyperLoopLabels slLabels = slLoop.getSLLabels();
SelfLoopPort alignRef = slLabels.getAlignmentReferenceSLPort();
KVector size = slLabels.getSize();
KVector pos = slLabels.getPosition();
switch(slLabels.getAlignment()) {
case CENTER:
pos.x = (slLoop.getSLHolder().getLNode().getSize().x - size.x) / 2;
break;
case LEFT:
pos.x = alignRef.getLPort().getPosition().x + alignRef.getLPort().getAnchor().x;
break;
case RIGHT:
pos.x = alignRef.getLPort().getPosition().x + alignRef.getLPort().getAnchor().x - size.x;
break;
case TOP:
pos.y = alignRef.getLPort().getPosition().y + alignRef.getLPort().getAnchor().y;
break;
default:
assert false;
}
}
use of org.eclipse.elk.alg.layered.intermediate.loops.SelfLoopPort in project elk by eclipse.
the class LabelPlacer method assignOneSidedSimpleSideAndAlignment.
/**
* Side and alignment assignment for those one-sided self loops where the choice is obvious. This is always the
* case for eastern and western self loops. For northern and southern self loops, this is the case if they are
* stacked.
*/
private void assignOneSidedSimpleSideAndAlignment(final SelfHyperLoop slLoop, final PortSide loopSide) {
switch(loopSide) {
case EAST:
case WEST:
// The alignment will be relative to the topmost port (which must be either the leftmost or the rightmost
// port)
SelfLoopPort topmostPort = slLoop.getLeftmostPort();
if (slLoop.getRightmostPort().getLPort().getPosition().y < topmostPort.getLPort().getPosition().y) {
topmostPort = slLoop.getRightmostPort();
}
assignSideAndAlignment(slLoop, loopSide, Alignment.TOP, topmostPort);
break;
case NORTH:
case SOUTH:
assignSideAndAlignment(slLoop, loopSide, Alignment.CENTER, null);
break;
default:
assert false;
}
}
Aggregations