use of org.eclipse.elk.alg.layered.graph.LEdge 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.LEdge 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.LEdge in project elk by eclipse.
the class CoffmanGrahamLayerer method dfs.
private void dfs(final LNode start, final LNode v) {
if (nodeMark[v.id]) {
return;
}
for (LEdge out : v.getOutgoingEdges()) {
LNode w = out.getTarget().getNode();
for (LEdge transitive : w.getIncomingEdges()) {
if (transitive.getSource().getNode() == start) {
edgeMark[transitive.id] = true;
}
}
dfs(start, w);
}
nodeMark[v.id] = true;
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class ElkGraphImporter method transformEdge.
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Edge Transformation
/**
* Transforms the given edge if it's not a hyperedge. If it is a hyperedge, throws an exception.
*
* @param elkedge the edge to transform
* @param elkparent the node in the original graph which currently gets transformed into {@code lgraph}
* @param lgraph the layered graph
* @return the transformed edge, or {@code null} if it cannot be transformed
* @throws UnsupportedGraphException if the edge is a hyperedge.
*/
private LEdge transformEdge(final ElkEdge elkedge, final ElkNode elkparent, final LGraph lgraph) {
checkEdgeValidity(elkedge);
// Get a few basic information about the edge
ElkConnectableShape elkSourceShape = elkedge.getSources().get(0);
ElkConnectableShape elkTargetShape = elkedge.getTargets().get(0);
ElkNode elkSourceNode = ElkGraphUtil.connectableShapeToNode(elkSourceShape);
ElkNode elkTargetNode = ElkGraphUtil.connectableShapeToNode(elkTargetShape);
ElkEdgeSection edgeSection = elkedge.getSections().isEmpty() ? null : elkedge.getSections().get(0);
// Find the transformed source and target nodes
LNode sourceLNode = (LNode) nodeAndPortMap.get(elkSourceNode);
LNode targetLNode = (LNode) nodeAndPortMap.get(elkTargetNode);
LPort sourceLPort = null;
LPort targetLPort = null;
// Find the transformed source port, if any
if (elkSourceShape instanceof ElkPort) {
// If the ElkPort is a regular port, it will map to an LPort; if it's an external port, it
// will map to an LNode
LGraphElement sourceElem = nodeAndPortMap.get(elkSourceShape);
if (sourceElem instanceof LPort) {
sourceLPort = (LPort) sourceElem;
} else if (sourceElem instanceof LNode) {
sourceLNode = (LNode) sourceElem;
sourceLPort = sourceLNode.getPorts().get(0);
}
}
// Find the transformed target port, if any
if (elkTargetShape instanceof ElkPort) {
// If the ElkPort is a regular port, it will map to an LPort; if it's an external port, it
// will map to an LNode
LGraphElement targetElem = nodeAndPortMap.get(elkTargetShape);
if (targetElem instanceof LPort) {
targetLPort = (LPort) targetElem;
} else if (targetElem instanceof LNode) {
targetLNode = (LNode) targetElem;
targetLPort = targetLNode.getPorts().get(0);
}
}
// reason, we back out
if (sourceLNode == null || targetLNode == null) {
throw new UnsupportedGraphException("The source or the target of edge " + elkedge + " could not be found. " + "This usually happens when an edge connects a node laid out by ELK Layered to a node in " + "another level of hierarchy laid out by either another instance of ELK Layered or another " + "layout algorithm alltogether. The former can be solved by setting the hierarchyHandling " + "option to INCLUDE_CHILDREN.");
}
// Create a layered edge
LEdge ledge = new LEdge();
ledge.copyProperties(elkedge);
ledge.setProperty(InternalProperties.ORIGIN, elkedge);
// Clear junction points, since they are recomputed from scratch
ledge.setProperty(LayeredOptions.JUNCTION_POINTS, null);
// If we have a self-loop, set the appropriate graph property
Set<GraphProperties> graphProperties = lgraph.getProperty(InternalProperties.GRAPH_PROPERTIES);
if (sourceLNode == targetLNode) {
graphProperties.add(GraphProperties.SELF_LOOPS);
}
// Create source and target ports if they do not exist yet
if (sourceLPort == null) {
PortType portType = PortType.OUTPUT;
KVector sourcePoint = null;
if (edgeSection != null && sourceLNode.getProperty(LayeredOptions.PORT_CONSTRAINTS).isSideFixed()) {
sourcePoint = new KVector(edgeSection.getStartX(), edgeSection.getStartY());
// The coordinates need to be relative to us
ElkUtil.toAbsolute(sourcePoint, elkedge.getContainingNode());
ElkUtil.toRelative(sourcePoint, elkparent);
// source), we may need to adjust the coordinates
if (ElkGraphUtil.isDescendant(elkTargetNode, elkSourceNode)) {
// External source port: put it on the west side
portType = PortType.INPUT;
sourcePoint.add(sourceLNode.getPosition());
}
}
sourceLPort = LGraphUtil.createPort(sourceLNode, sourcePoint, portType, lgraph);
}
if (targetLPort == null) {
PortType portType = PortType.INPUT;
KVector targetPoint = null;
if (edgeSection != null && targetLNode.getProperty(LayeredOptions.PORT_CONSTRAINTS).isSideFixed()) {
targetPoint = new KVector(edgeSection.getEndX(), edgeSection.getEndY());
// Adjust the coordinates
// MIGRATE Not sure yet if this really does what we want it to do
ElkUtil.toAbsolute(targetPoint, elkedge.getContainingNode());
ElkUtil.toRelative(targetPoint, elkparent);
}
targetLPort = LGraphUtil.createPort(targetLNode, targetPoint, portType, targetLNode.getGraph());
}
// Finally set the source and target of the edge
ledge.setSource(sourceLPort);
ledge.setTarget(targetLPort);
// If the ports have multiple incoming or outgoing edges, the HYPEREDGE property needs to be set
if (sourceLPort.getIncomingEdges().size() > 1 || sourceLPort.getOutgoingEdges().size() > 1 || targetLPort.getIncomingEdges().size() > 1 || targetLPort.getOutgoingEdges().size() > 1) {
graphProperties.add(GraphProperties.HYPEREDGES);
}
// Transform the edge's labels
for (ElkLabel elklabel : elkedge.getLabels()) {
if (!elklabel.getProperty(LayeredOptions.NO_LAYOUT) && !Strings.isNullOrEmpty(elklabel.getText())) {
LLabel llabel = transformLabel(elklabel);
ledge.getLabels().add(llabel);
// edge label placement is actually properly defined
switch(llabel.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT)) {
case HEAD:
case TAIL:
graphProperties.add(GraphProperties.END_LABELS);
break;
case CENTER:
graphProperties.add(GraphProperties.CENTER_LABELS);
llabel.setProperty(LayeredOptions.EDGE_LABELS_PLACEMENT, EdgeLabelPlacement.CENTER);
}
}
}
// Copy the original bend points of the edge in case they are required
CrossingMinimizationStrategy crossMinStrat = lgraph.getProperty(LayeredOptions.CROSSING_MINIMIZATION_STRATEGY);
NodePlacementStrategy nodePlaceStrat = lgraph.getProperty(LayeredOptions.NODE_PLACEMENT_STRATEGY);
boolean bendPointsRequired = crossMinStrat == CrossingMinimizationStrategy.INTERACTIVE || nodePlaceStrat == NodePlacementStrategy.INTERACTIVE;
if (edgeSection != null && !edgeSection.getBendPoints().isEmpty() && bendPointsRequired) {
KVectorChain originalBendpoints = ElkUtil.createVectorChain(edgeSection);
KVectorChain importedBendpoints = new KVectorChain();
// MIGRATE We may have to do some coordinate conversion here
for (KVector point : originalBendpoints) {
importedBendpoints.add(new KVector(point));
}
ledge.setProperty(InternalProperties.ORIGINAL_BENDPOINTS, importedBendpoints);
}
return ledge;
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class ElkGraphImporter method importHierarchicalGraph.
/**
* Imports the graph hierarchy rooted at the given graph.
*
* @param elkgraph
* graph to import.
* @param lgraph
* graph to add the direct children of the current hierarchy level to.
*/
private void importHierarchicalGraph(final ElkNode elkgraph, final LGraph lgraph) {
final Queue<ElkNode> elkGraphQueue = Lists.newLinkedList();
Direction parentGraphDirection = lgraph.getProperty(LayeredOptions.DIRECTION);
// Model order index for nodes
int index = 0;
// Transform the node's children
elkGraphQueue.addAll(elkgraph.getChildren());
while (!elkGraphQueue.isEmpty()) {
ElkNode elknode = elkGraphQueue.poll();
if (elkgraph.getProperty(LayeredOptions.CONSIDER_MODEL_ORDER_STRATEGY) != OrderingStrategy.NONE || elkgraph.getProperty(LayeredOptions.CYCLE_BREAKING_STRATEGY) == CycleBreakingStrategy.MODEL_ORDER) {
// Assign a model order to the nodes as they are read
elknode.setProperty(InternalProperties.MODEL_ORDER, index++);
}
// Check if the current node is to be laid out in the first place
boolean isNodeToBeLaidOut = !elknode.getProperty(LayeredOptions.NO_LAYOUT);
if (isNodeToBeLaidOut) {
// Check if there has to be an LGraph for this node (which is the case if it has children or inside
// self-loops, and if it does not have another layout algorithm configured)
boolean hasChildren = !elknode.getChildren().isEmpty();
boolean hasInsideSelfLoops = hasInsideSelfLoops(elknode);
boolean hasHierarchyHandlingEnabled = elknode.getProperty(LayeredOptions.HIERARCHY_HANDLING) == HierarchyHandling.INCLUDE_CHILDREN;
boolean usesElkLayered = !elknode.hasProperty(CoreOptions.ALGORITHM) || elknode.getProperty(CoreOptions.ALGORITHM).equals(LayeredOptions.ALGORITHM_ID);
LGraph nestedGraph = null;
if (usesElkLayered && hasHierarchyHandlingEnabled && (hasChildren || hasInsideSelfLoops)) {
nestedGraph = createLGraph(elknode);
nestedGraph.setProperty(LayeredOptions.DIRECTION, parentGraphDirection);
// Apply a spacing configuration, for details see comment int #importGraph(...)
if (nestedGraph.hasProperty(LayeredOptions.SPACING_BASE_VALUE)) {
LayeredSpacings.withBaseValue(nestedGraph.getProperty(LayeredOptions.SPACING_BASE_VALUE)).apply(nestedGraph);
}
// if the size constraints are not empty
if (shouldCalculateMinimumGraphSize(elknode)) {
final LGraph finalNestedGraph = nestedGraph;
elknode.getPorts().stream().forEach(elkport -> ensureDefinedPortSide(finalNestedGraph, elkport));
calculateMinimumGraphSize(elknode, nestedGraph);
}
}
// Transform da node!!!
LGraph parentLGraph = lgraph;
LNode parentLNode = (LNode) nodeAndPortMap.get(elknode.getParent());
if (parentLNode != null) {
parentLGraph = parentLNode.getNestedGraph();
}
LNode lnode = transformNode(elknode, parentLGraph);
// Setup hierarchical relationships
if (nestedGraph != null) {
lnode.setNestedGraph(nestedGraph);
nestedGraph.setParentNode(lnode);
elkGraphQueue.addAll(elknode.getChildren());
}
}
}
// Model order index for edges.
index = 0;
// Transform the edges
elkGraphQueue.add(elkgraph);
while (!elkGraphQueue.isEmpty()) {
ElkNode elkGraphNode = elkGraphQueue.poll();
for (ElkEdge elkedge : elkGraphNode.getContainedEdges()) {
// We don't support hyperedges
checkEdgeValidity(elkedge);
if (elkgraph.getProperty(LayeredOptions.CONSIDER_MODEL_ORDER_STRATEGY) != OrderingStrategy.NONE || elkgraph.getProperty(LayeredOptions.CYCLE_BREAKING_STRATEGY) == CycleBreakingStrategy.MODEL_ORDER) {
// Assign a model order to the edges as they are read
elkedge.setProperty(InternalProperties.MODEL_ORDER, index++);
}
ElkNode sourceNode = ElkGraphUtil.connectableShapeToNode(elkedge.getSources().get(0));
ElkNode targetNode = ElkGraphUtil.connectableShapeToNode(elkedge.getTargets().get(0));
// Don't bother if either the edge or at least one of its end points are excluded from layout
if (elkedge.getProperty(LayeredOptions.NO_LAYOUT) || sourceNode.getProperty(LayeredOptions.NO_LAYOUT) || targetNode.getProperty(LayeredOptions.NO_LAYOUT)) {
continue;
}
// Check if this edge is an inside self-loop
boolean isInsideSelfLoop = elkedge.isSelfloop() && sourceNode.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_ACTIVATE) && elkedge.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_YO);
// Find the graph the edge will be placed in. Basically, if the edge is an inside
// self loop or connects one of its end points to a descendant, the edge will be
// placed in the graph that represents that end point's insides. Otherwise, it will
// be placed in the current graph.
ElkNode parentElkGraph = elkGraphNode;
if (isInsideSelfLoop || ElkGraphUtil.isDescendant(targetNode, sourceNode)) {
parentElkGraph = sourceNode;
} else if (ElkGraphUtil.isDescendant(sourceNode, targetNode)) {
parentElkGraph = targetNode;
}
LGraph parentLGraph = lgraph;
LNode parentLNode = (LNode) nodeAndPortMap.get(parentElkGraph);
if (parentLNode != null) {
parentLGraph = parentLNode.getNestedGraph();
}
// Transform the edge, finally...
LEdge ledge = transformEdge(elkedge, parentElkGraph, parentLGraph);
// Find the graph the edge's coordinates will have to be made relative to during export. This will only
// do something if the edge containment inside ELK Layered differs from the edge containment in the
// ELK graph
ledge.setProperty(InternalProperties.COORDINATE_SYSTEM_ORIGIN, findCoordinateSystemOrigin(elkedge, elkgraph, lgraph));
}
// We may need to look at edges contained in the current graph node's children as well.
// this is true unless either the current graph node does not have hierarchy handling
// enabled, or a child has another layout algorithm configured
boolean hasHierarchyHandlingEnabled = elkGraphNode.getProperty(LayeredOptions.HIERARCHY_HANDLING) == HierarchyHandling.INCLUDE_CHILDREN;
if (hasHierarchyHandlingEnabled) {
for (ElkNode elkChildGraphNode : elkGraphNode.getChildren()) {
boolean usesElkLayered = !elkChildGraphNode.hasProperty(CoreOptions.ALGORITHM) || elkChildGraphNode.getProperty(CoreOptions.ALGORITHM).equals(LayeredOptions.ALGORITHM_ID);
boolean partOfSameLayoutRun = elkChildGraphNode.getProperty(LayeredOptions.HIERARCHY_HANDLING) == HierarchyHandling.INCLUDE_CHILDREN;
if (usesElkLayered && partOfSameLayoutRun) {
elkGraphQueue.add(elkChildGraphNode);
}
}
}
}
}
Aggregations