use of org.eclipse.elk.alg.layered.graph.LPort in project elk by eclipse.
the class CuttingUtils method insertDummies.
/**
* Inserts two in-layer dummies and a varying number of long edge dummies for the passed edge.
*
* Let {@code originalEdge = e = (u,v)}. In-layer dummies {@code il_1} and {@code il_2} are inserted into layers
* {@code L(u)} and {@code L(v)}. Long edge dummies {@code d_1, ..., d_m} are inserted into the layers
* {@code L(u)+1, ..., L(v)-1}.
*
* The resulting chain of edges looks as follows (if {@code offsetFirstInLayerDummy} is 1).
*
* <pre>
* v
* î
* il_1 -> d_1 -> ... -> d_m -> il_2
* î
* u
* </pre>
*
* @param layeredGraph
* the underlying graph with a given layering.
* @param originalEdge
* the edge to be split
* @param offsetFirstInLayerDummy
* the dummy nodes are inserted at the end of each layer. For the first in-layer dummy this is not always
* desired and can be modified using this offset.
*/
public static List<LEdge> insertDummies(final LGraph layeredGraph, final LEdge originalEdge, final int offsetFirstInLayerDummy) {
// to visually separate the backward wrapping edges, add some additional spacing
double edgeNodeSpacing = layeredGraph.getProperty(LayeredOptions.SPACING_EDGE_NODE);
double additionalSpacing = layeredGraph.getProperty(LayeredOptions.WRAPPING_ADDITIONAL_EDGE_SPACING);
IndividualSpacings is = new IndividualSpacings();
is.setProperty(LayeredOptions.SPACING_EDGE_NODE, edgeNodeSpacing + additionalSpacing);
LEdge edge = originalEdge;
LPort targetPort = edge.getTarget();
LNode src = edge.getSource().getNode();
LNode tgt = edge.getTarget().getNode();
int srcIndex = src.getLayer().getIndex();
int tgtIndex = tgt.getLayer().getIndex();
List<LEdge> createdEdges = Lists.newArrayList();
for (int i = srcIndex; i <= tgtIndex; i++) {
// Create dummy node
LNode dummyNode = new LNode(layeredGraph);
dummyNode.setType(NodeType.LONG_EDGE);
dummyNode.setProperty(InternalProperties.ORIGIN, edge);
dummyNode.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS);
dummyNode.setProperty(LayeredOptions.SPACING_INDIVIDUAL, is);
Layer nextLayer = layeredGraph.getLayers().get(i);
if (i == srcIndex) {
dummyNode.setLayer(nextLayer.getNodes().size() - offsetFirstInLayerDummy, nextLayer);
} else {
dummyNode.setLayer(nextLayer);
}
// Set thickness of the edge
double thickness = edge.getProperty(LayeredOptions.EDGE_THICKNESS);
if (thickness < 0) {
thickness = 0;
edge.setProperty(LayeredOptions.EDGE_THICKNESS, thickness);
}
dummyNode.getSize().y = thickness;
double portPos = Math.floor(thickness / 2);
// Create dummy input and output ports
LPort dummyInput = new LPort();
dummyInput.setSide(PortSide.WEST);
dummyInput.setNode(dummyNode);
dummyInput.getPosition().y = portPos;
LPort dummyOutput = new LPort();
dummyOutput.setSide(PortSide.EAST);
dummyOutput.setNode(dummyNode);
dummyOutput.getPosition().y = portPos;
edge.setTarget(dummyInput);
// Create a dummy edge
LEdge dummyEdge = new LEdge();
dummyEdge.copyProperties(edge);
dummyEdge.setProperty(LayeredOptions.JUNCTION_POINTS, null);
dummyEdge.setSource(dummyOutput);
dummyEdge.setTarget(targetPort);
setDummyProperties(dummyNode, edge, dummyEdge);
createdEdges.add(dummyEdge);
edge = dummyEdge;
}
return createdEdges;
}
use of org.eclipse.elk.alg.layered.graph.LPort in project elk by eclipse.
the class GreedyPortDistributor method distributePortsOnNode.
/**
* Distribute ports greedily on a single node.
*/
private boolean distributePortsOnNode(final LNode node, final PortSide side, final boolean useHierarchicalCrosscounter) {
List<LPort> ports = node.getPortSideView(side);
if (side == PortSide.SOUTH || side == PortSide.WEST) {
ports = Lists.reverse(ports);
}
boolean improved = false;
boolean continueSwitching;
do {
continueSwitching = false;
for (int i = 0; i < ports.size() - 1; i++) {
LPort upperPort = ports.get(i);
LPort lowerPort = ports.get(i + 1);
if (switchingDecreasesCrossings(upperPort, lowerPort, node, useHierarchicalCrosscounter)) {
improved = true;
switchPorts(ports, node, i, i + 1);
continueSwitching = true;
}
}
} while (continueSwitching);
return improved;
}
use of org.eclipse.elk.alg.layered.graph.LPort in project elk by eclipse.
the class GreedyCycleBreaker method updateNeighbors.
/**
* Updates indegree and outdegree values of the neighbors of the given node,
* simulating its removal from the graph. the sources and sinks lists are
* also updated.
*
* @param node node for which neighbors are updated
*/
private void updateNeighbors(final LNode node) {
for (LPort port : node.getPorts()) {
for (LEdge edge : port.getConnectedEdges()) {
LPort connectedPort = edge.getSource() == port ? edge.getTarget() : edge.getSource();
LNode endpoint = connectedPort.getNode();
// exclude self-loops
if (node == endpoint) {
continue;
}
int priority = edge.getProperty(LayeredOptions.PRIORITY_DIRECTION);
if (priority < 0) {
priority = 0;
}
int index = endpoint.id;
if (mark[index] == 0) {
if (edge.getTarget() == connectedPort) {
indeg[index] -= priority + 1;
if (indeg[index] <= 0 && outdeg[index] > 0) {
sources.add(endpoint);
}
} else {
outdeg[index] -= priority + 1;
if (outdeg[index] <= 0 && indeg[index] > 0) {
sinks.add(endpoint);
}
}
}
}
}
}
use of org.eclipse.elk.alg.layered.graph.LPort in project elk by eclipse.
the class InteractiveCycleBreaker method process.
@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Interactive cycle breaking", 1);
// gather edges that point to the wrong direction
List<LEdge> revEdges = Lists.newArrayList();
for (LNode source : layeredGraph.getLayerlessNodes()) {
source.id = 1;
double sourcex = source.getInteractiveReferencePoint().x;
for (LPort port : source.getPorts(PortType.OUTPUT)) {
for (LEdge edge : port.getOutgoingEdges()) {
LNode target = edge.getTarget().getNode();
if (target != source) {
double targetx = target.getInteractiveReferencePoint().x;
if (targetx < sourcex) {
revEdges.add(edge);
}
}
}
}
}
// reverse the gathered edges
for (LEdge edge : revEdges) {
edge.reverse(layeredGraph, true);
}
// perform an additional check for cycles - maybe we missed something
// (could happen if some nodes have the same horizontal position)
revEdges.clear();
for (LNode node : layeredGraph.getLayerlessNodes()) {
// unvisited nodes have id = 1
if (node.id > 0) {
findCycles(node, revEdges);
}
}
// again, reverse the edges that were marked
for (LEdge edge : revEdges) {
edge.reverse(layeredGraph, true);
}
revEdges.clear();
monitor.done();
}
use of org.eclipse.elk.alg.layered.graph.LPort in project elk by eclipse.
the class SweepCopy method assertCorrectPortSides.
/**
* Corrects the {@link PortSide} of dummy's origin.
* @return The {@link LNode} ('origin') whose port {@code dummy} represents.
*/
private LNode assertCorrectPortSides(final LNode dummy) {
assert dummy.getType() == NodeType.NORTH_SOUTH_PORT;
LNode origin = dummy.getProperty(InternalProperties.IN_LAYER_LAYOUT_UNIT);
// a north south port dummy has exactly one port
List<LPort> dummyPorts = dummy.getPorts();
LPort dummyPort = dummyPorts.get(0);
// find the corresponding port on the regular node
for (LPort port : origin.getPorts()) {
if (port.equals(dummyPort.getProperty(InternalProperties.ORIGIN))) {
// switch the port's side if necessary
if ((port.getSide() == PortSide.NORTH) && (dummy.id > origin.id)) {
port.setSide(PortSide.SOUTH);
if (port.isExplicitlySuppliedPortAnchor()) {
// Set new coordinates for port anchor since it was switched from NORTH to SOUTH.
// The y coordinate is updated by mirroring the y coordinate
double portHeight = port.getSize().y;
double anchorY = port.getAnchor().y;
port.getAnchor().y = portHeight - anchorY;
}
} else if ((port.getSide() == PortSide.SOUTH) && (origin.id > dummy.id)) {
port.setSide(PortSide.NORTH);
if (port.isExplicitlySuppliedPortAnchor()) {
// Set new coordinates for port anchor since it was switched from NORTH to SOUTH.
// The y coordinate is updated by mirroring the y coordinate
double portHeight = port.getSize().y;
double anchorY = port.getAnchor().y;
port.getAnchor().y = -(portHeight - anchorY);
}
}
break;
}
}
return origin;
}
Aggregations