use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class CommentPreprocessor method process.
@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Comment pre-processing", 1);
int commentBoxCount = 0;
Iterator<LNode> nodeIter = layeredGraph.getLayerlessNodes().iterator();
while (nodeIter.hasNext()) {
LNode node = nodeIter.next();
if (node.getProperty(LayeredOptions.COMMENT_BOX)) {
commentBoxCount++;
int edgeCount = 0;
LEdge edge = null;
LPort oppositePort = null;
for (LPort port : node.getPorts()) {
edgeCount += port.getDegree();
if (port.getIncomingEdges().size() == 1) {
edge = port.getIncomingEdges().get(0);
oppositePort = edge.getSource();
}
if (port.getOutgoingEdges().size() == 1) {
edge = port.getOutgoingEdges().get(0);
oppositePort = edge.getTarget();
}
}
if (edgeCount == 1 && oppositePort.getDegree() == 1 && !oppositePort.getNode().getProperty(LayeredOptions.COMMENT_BOX)) {
// found a comment that has exactly one connection
processBox(node, edge, oppositePort, oppositePort.getNode());
nodeIter.remove();
} else {
// reverse edges that are oddly connected
List<LEdge> revEdges = Lists.newArrayList();
for (LPort port : node.getPorts()) {
for (LEdge outedge : port.getOutgoingEdges()) {
if (!outedge.getTarget().getOutgoingEdges().isEmpty()) {
revEdges.add(outedge);
}
}
for (LEdge inedge : port.getIncomingEdges()) {
if (!inedge.getSource().getIncomingEdges().isEmpty()) {
revEdges.add(inedge);
}
}
}
for (LEdge re : revEdges) {
re.reverse(layeredGraph, true);
}
}
}
}
if (monitor.isLoggingEnabled()) {
monitor.log("Found " + commentBoxCount + " comment boxes");
}
monitor.done();
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class CompoundGraphPreprocessor method moveLabelsAndRemoveOriginalEdges.
/**
* Moves all labels of the original edges to the appropriate dummy edges and removes the
* original edges from the graph.
*
* @param graph
* the top-level graph.
*/
private void moveLabelsAndRemoveOriginalEdges(final LGraph graph) {
// edges from the graph
for (LEdge origEdge : crossHierarchyMap.keySet()) {
// segments
if (origEdge.getLabels().size() > 0) {
// retrieve and sort the edge segments introduced for the original edge
List<CrossHierarchyEdge> edgeSegments = new ArrayList<CrossHierarchyEdge>(crossHierarchyMap.get(origEdge));
Collections.sort(edgeSegments, new CrossHierarchyEdgeComparator(graph));
// iterate over the labels and move them to the edge segments
Iterator<LLabel> labelIterator = origEdge.getLabels().listIterator();
while (labelIterator.hasNext()) {
LLabel currLabel = labelIterator.next();
// find the index of the dummy edge we will move the label to
int targetDummyEdgeIndex = -1;
switch(currLabel.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT)) {
case HEAD:
targetDummyEdgeIndex = edgeSegments.size() - 1;
break;
case CENTER:
targetDummyEdgeIndex = getShallowestEdgeSegment(edgeSegments);
break;
case TAIL:
targetDummyEdgeIndex = 0;
break;
default:
}
// move the label if we were lucky enough to find a new home for it
if (targetDummyEdgeIndex != -1) {
CrossHierarchyEdge targetSegment = edgeSegments.get(targetDummyEdgeIndex);
targetSegment.getEdge().getLabels().add(currLabel);
targetSegment.getEdge().getSource().getNode().getGraph().getProperty(InternalProperties.GRAPH_PROPERTIES).add(GraphProperties.END_LABELS);
targetSegment.getEdge().getSource().getNode().getGraph().getProperty(InternalProperties.GRAPH_PROPERTIES).add(GraphProperties.CENTER_LABELS);
labelIterator.remove();
currLabel.setProperty(InternalProperties.ORIGINAL_LABEL_EDGE, origEdge);
}
}
}
// remove original edge
origEdge.setSource(null);
origEdge.setTarget(null);
}
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class CompoundGraphPreprocessor method connectSiblings.
/**
* Connects external ports of two child nodes of the given graph. To this end, the provided list
* of external ports is searched for the counterpart of the provided external output port, and a
* new dummy edge is created to connect the two. The dummy edge is associated with the original
* hierarchy-crossing edge in the cross hierarchy map.
*
* @param graph
* the graph whose child nodes to connect.
* @param externalOutputPort
* the external output port.
* @param containedExternalPorts
* list of external ports exposed by children of the graph. This list is searched for
* the external target port.
* @param origEdge
* the original edge that is being broken.
*/
private void connectSiblings(final LGraph graph, final ExternalPort externalOutputPort, final List<ExternalPort> containedExternalPorts, final LEdge origEdge) {
// find the opposite external port
ExternalPort targetExternalPort = null;
for (ExternalPort externalPort2 : containedExternalPorts) {
if (externalPort2 != externalOutputPort && externalPort2.origEdges.contains(origEdge)) {
targetExternalPort = externalPort2;
break;
}
}
assert targetExternalPort.type == PortType.INPUT;
// add new dummy edge and connect properly
LEdge dummyEdge = createDummyEdge(graph, origEdge);
dummyEdge.setSource(externalOutputPort.dummyPort);
dummyEdge.setTarget(targetExternalPort.dummyPort);
crossHierarchyMap.put(origEdge, new CrossHierarchyEdge(dummyEdge, graph, externalOutputPort.type));
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class CompoundGraphPreprocessor method introduceHierarchicalEdgeSegment.
// //////////////////////////////////////////////////////////////////////////////////////////
// General Hierarchical Edge Segment Processing
/**
* Does the actual work of creating a new hierarchical edge segment between an external port and
* a given opposite port. The external port used for the segment is returned. This method does
* not put any created edges into the cross hierarchy map!
*
* <p>
* The method first decides on an external port to use for the segment. If the default external
* port passed to the method is not {@code null} and if external ports are to be merged in the
* current graph, the default external port is reused. An exception are segments that start or
* end in the parent node; each such segments gets its own external port.
* </p>
*
* <p>
* If a new external port is created, the method also creates a dummy node for it as well as an
* actual port on the parent node, if no such port already exists, as well as a dummy edge for
* the connection. Thus, the newly created external port has everything it needs to be properly
* represented and initialized.
* </p>
*
* <p>
* The original edge is added to the list of original edges in the external port used for the
* segment. The dummy edge is associated with the original hierarchy-crossing edge in the cross
* hierarchy map.
* </p>
*
* @param graph
* the layered graph.
* @param parentNode
* the graph's parent node, or {@code null} if the graph is at the top level.
* @param origEdge
* the hierarchy-crossing edge that is being broken.
* @param oppositePort
* the port that will be one of the two end points of the new segment.
* @param portType
* the type of the port to create as one of the segment's edge points.
* @param defaultExternalPort
* a default external port we can reuse if external ports should be merged. If this
* is {@code null}, a new external port is always created. If this port is reused, it
* is returned by this method.
* @return the (created or reused) external port used as one endpoint of the edge segment.
*/
private ExternalPort introduceHierarchicalEdgeSegment(final LGraph graph, final LNode parentNode, final LEdge origEdge, final LPort oppositePort, final PortType portType, final ExternalPort defaultExternalPort) {
// check if external ports are to be merged
boolean mergeExternalPorts = graph.getProperty(LayeredOptions.MERGE_HIERARCHY_EDGES);
// check if the edge connects to the parent node instead of to the outside world; if so, the
// parentEndPort will be non-null
LPort parentEndPort = null;
if (portType == PortType.INPUT && origEdge.getSource().getNode() == parentNode) {
parentEndPort = origEdge.getSource();
} else if (portType == PortType.OUTPUT && origEdge.getTarget().getNode() == parentNode) {
parentEndPort = origEdge.getTarget();
}
// only create a new external port if the current one is null or if ports are not to be merged
// or if the connection actually ends at the parent node
ExternalPort externalPort = defaultExternalPort;
if (externalPort == null || !mergeExternalPorts || parentEndPort != null) {
// create a dummy node that will represent the external port
PortSide externalPortSide = PortSide.UNDEFINED;
if (parentEndPort != null) {
externalPortSide = parentEndPort.getSide();
} else {
// for people to set compound node port constraints to FREE
if (parentNode.getProperty(LayeredOptions.PORT_CONSTRAINTS).isSideFixed()) {
externalPortSide = portType == PortType.INPUT ? PortSide.WEST : PortSide.EAST;
}
}
LNode dummyNode = createExternalPortDummy(graph, parentNode, portType, externalPortSide, origEdge);
// create a dummy edge to be connected to the port
LEdge dummyEdge = createDummyEdge(parentNode.getGraph(), origEdge);
if (portType == PortType.INPUT) {
// if the external port is an input port, the source of the edge must be connected to
// the new dummy node
dummyEdge.setSource(dummyNode.getPorts().get(0));
dummyEdge.setTarget(oppositePort);
} else {
// if the external port is an output port, the target of the edge must be connected to
// the new dummy node
dummyEdge.setSource(oppositePort);
dummyEdge.setTarget(dummyNode.getPorts().get(0));
}
// create the external port (the port is to be exported if the connection is not just to the
// parent node)
externalPort = new ExternalPort(origEdge, dummyEdge, dummyNode, (LPort) dummyNode.getProperty(InternalProperties.ORIGIN), portType, parentEndPort == null);
} else {
// we use an existing external port, so simply add the original edge to its list of
// original edges
externalPort.origEdges.add(origEdge);
// merge the properties of the original edges
double thickness = Math.max(externalPort.newEdge.getProperty(LayeredOptions.EDGE_THICKNESS), origEdge.getProperty(LayeredOptions.EDGE_THICKNESS));
externalPort.newEdge.setProperty(LayeredOptions.EDGE_THICKNESS, thickness);
}
crossHierarchyMap.put(origEdge, new CrossHierarchyEdge(externalPort.newEdge, graph, portType));
return externalPort;
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class DummySelfLoopProcessor method createDummy.
/**
* Creates a dummy for the self-loop edge connecting the two given ports. The dummy is not
* added to the layer yet.
*
* @param layeredGraph the layered graph.
* @param edge the self-looping edge.
* @param sourcePort the source port.
* @param targetPort the target port.
* @return the dummy node created.
*/
private LNode createDummy(final LGraph layeredGraph, final LEdge edge, final LPort sourcePort, final LPort targetPort) {
// Create a dummy node with an input port and an output port
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(InternalProperties.LONG_EDGE_SOURCE, sourcePort);
dummyNode.setProperty(InternalProperties.LONG_EDGE_TARGET, targetPort);
LPort dummyInput = new LPort();
dummyInput.setSide(PortSide.WEST);
dummyInput.setNode(dummyNode);
LPort dummyOutput = new LPort();
dummyOutput.setSide(PortSide.EAST);
dummyOutput.setNode(dummyNode);
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);
return dummyNode;
}
Aggregations