use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.
the class ElkGraphImporter method checkExternalPorts.
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// External Port Transformation
/**
* Checks if external ports processing should be active. This is the case if the parent node has
* ports and at least one of the following conditions is true:
* <ul>
* <li>
* Port label placement is set to {@code INSIDE} and at least one of the ports has a label.
* </li>
* <li>
* At least one of the ports has an edge that connects to the insides of the parent node.
* </li>
* <li>
* There is a self-loop that should be routed inside the node.
* </li>
* </ul>
*
* @param elkgraph
* a KGraph we want to check for external ports.
* @param graphProperties
* the set of graph properties to store our results in.
*/
private void checkExternalPorts(final ElkNode elkgraph, final Set<GraphProperties> graphProperties) {
final boolean enableSelfLoops = elkgraph.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_ACTIVATE);
final Set<PortLabelPlacement> portLabelPlacement = elkgraph.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT);
// We're iterating over the ports until we've determined that we have both external ports and
// hyperedges, or if there are no more ports left
boolean hasExternalPorts = false;
boolean hasHyperedges = false;
final Iterator<ElkPort> portIterator = elkgraph.getPorts().iterator();
while (portIterator.hasNext() && (!hasExternalPorts || !hasHyperedges)) {
final ElkPort elkport = portIterator.next();
// Find out if there are edges connected to external ports of the graph (this is the case
// for inside self loops as well as for edges connected to children)
int externalPortEdges = 0;
for (ElkEdge elkedge : ElkGraphUtil.allIncidentEdges(elkport)) {
boolean isInsideSelfLoop = enableSelfLoops && elkedge.isSelfloop() && elkedge.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_YO);
boolean connectsToChild = elkedge.getSources().contains(elkport) ? elkgraph == ElkGraphUtil.connectableShapeToNode(elkedge.getTargets().get(0)).getParent() : elkgraph == ElkGraphUtil.connectableShapeToNode(elkedge.getSources().get(0)).getParent();
if (isInsideSelfLoop || connectsToChild) {
externalPortEdges++;
if (externalPortEdges > 1) {
break;
}
}
}
// External ports?
if (externalPortEdges > 0) {
hasExternalPorts = true;
} else if (portLabelPlacement.contains(PortLabelPlacement.INSIDE) && elkport.getLabels().size() > 0) {
hasExternalPorts = true;
}
// Hyperedges, even?
if (externalPortEdges > 1) {
hasHyperedges = true;
}
}
// Update graph properties
if (hasExternalPorts) {
graphProperties.add(GraphProperties.EXTERNAL_PORTS);
}
if (hasHyperedges) {
graphProperties.add(GraphProperties.HYPEREDGES);
}
}
use of org.eclipse.elk.graph.ElkEdge 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);
}
}
}
}
}
use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.
the class ElkGraphImporter method applyLayout.
// /////////////////////////////////////////////////////////////////////////////
// Apply Layout Results
@Override
public void applyLayout(final TGraph tGraph) {
// get the corresponding kGraph
ElkNode elkgraph = (ElkNode) tGraph.getProperty(InternalProperties.ORIGIN);
// calculate the offset from border spacing and node distribution
double minXPos = Integer.MAX_VALUE;
double minYPos = Integer.MAX_VALUE;
double maxXPos = Integer.MIN_VALUE;
double maxYPos = Integer.MIN_VALUE;
for (TNode tNode : tGraph.getNodes()) {
KVector pos = tNode.getPosition();
KVector size = tNode.getSize();
minXPos = Math.min(minXPos, pos.x - size.x / 2);
minYPos = Math.min(minYPos, pos.y - size.y / 2);
maxXPos = Math.max(maxXPos, pos.x + size.x / 2);
maxYPos = Math.max(maxYPos, pos.y + size.y / 2);
}
ElkPadding padding = elkgraph.getProperty(MrTreeOptions.PADDING);
KVector offset = new KVector(padding.getLeft() - minXPos, padding.getTop() - minYPos);
// process the nodes
for (TNode tNode : tGraph.getNodes()) {
Object object = tNode.getProperty(InternalProperties.ORIGIN);
if (object instanceof ElkNode) {
// set the node position
ElkNode elknode = (ElkNode) object;
KVector nodePos = tNode.getPosition().add(offset);
elknode.setLocation(nodePos.x - elknode.getWidth() / 2, nodePos.y - elknode.getHeight() / 2);
}
}
// process the edges
for (TEdge tEdge : tGraph.getEdges()) {
ElkEdge elkedge = (ElkEdge) tEdge.getProperty(InternalProperties.ORIGIN);
if (elkedge != null) {
KVectorChain bendPoints = tEdge.getBendPoints();
// add the source port and target points to the vector chain
KVector sourcePoint = new KVector(tEdge.getSource().getPosition());
bendPoints.addFirst(sourcePoint);
KVector targetPoint = new KVector(tEdge.getTarget().getPosition());
bendPoints.addLast(targetPoint);
// correct the source and target points
toNodeBorder(sourcePoint, bendPoints.get(1), tEdge.getSource().getSize());
toNodeBorder(targetPoint, bendPoints.get(bendPoints.size() - 2), tEdge.getTarget().getSize());
ElkEdgeSection edgeSection = ElkGraphUtil.firstEdgeSection(elkedge, true, true);
ElkUtil.applyVectorChain(bendPoints, edgeSection);
}
}
// set up the graph
double width = maxXPos - minXPos + padding.getHorizontal();
double height = maxYPos - minYPos + padding.getVertical();
ElkUtil.resizeNode(elkgraph, width, height, false, false);
}
use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.
the class ElkUtil method printElementPath.
// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DEBUGGING
/**
* Print information on the given graph element to the given string builder.
*/
public static void printElementPath(final ElkGraphElement element, final StringBuilder builder) {
// Print the containing element
if (element.eContainer() instanceof ElkGraphElement) {
printElementPath((ElkGraphElement) element.eContainer(), builder);
builder.append(" > ");
} else {
builder.append("Root ");
}
// Print the class name
String className = element.eClass().getName();
if (className.startsWith("Elk")) {
// CHECKSTYLEOFF MagicNumber
builder.append(className.substring(3));
// CHECKSTYLEON MagicNumber
} else {
builder.append(className);
}
// Print the identifier if present
String identifier = element.getIdentifier();
if (!Strings.isNullOrEmpty(identifier)) {
builder.append(' ').append(identifier);
return;
}
// Print the label if present
if (element instanceof ElkLabel) {
String text = ((ElkLabel) element).getText();
if (!Strings.isNullOrEmpty(text)) {
builder.append(' ').append(text);
return;
}
}
for (ElkLabel label : element.getLabels()) {
String text = label.getText();
if (!Strings.isNullOrEmpty(text)) {
builder.append(' ').append(text);
return;
}
}
// If it's an edge and no identifier nor label is present, print source and target
if (element instanceof ElkEdge) {
ElkEdge edge = (ElkEdge) element;
if (edge.isConnected()) {
builder.append(" (");
ListIterator<ElkConnectableShape> sourceIter = edge.getSources().listIterator();
while (sourceIter.hasNext()) {
if (sourceIter.nextIndex() > 0) {
builder.append(", ");
}
printElementPath(sourceIter.next(), builder);
}
builder.append(" -> ");
ListIterator<ElkConnectableShape> targetIter = edge.getTargets().listIterator();
while (targetIter.hasNext()) {
if (targetIter.nextIndex() > 0) {
builder.append(", ");
}
printElementPath(targetIter.next(), builder);
}
builder.append(")");
}
}
}
use of org.eclipse.elk.graph.ElkEdge in project elk by eclipse.
the class FixedLayoutProvider method layout.
@Override
public void layout(final ElkNode layoutNode, final IElkProgressMonitor progressMonitor) {
progressMonitor.begin("Fixed Layout", 1);
EdgeRouting edgeRouting = layoutNode.getProperty(CoreOptions.EDGE_ROUTING);
double maxx = 0;
double maxy = 0;
for (ElkNode node : layoutNode.getChildren()) {
// set the fixed position of the node, or leave it as it is
KVector pos = node.getProperty(FixedLayouterOptions.POSITION);
if (pos != null) {
node.setLocation(pos.x, pos.y);
// set the fixed size of the node
if (node.getProperty(FixedLayouterOptions.NODE_SIZE_CONSTRAINTS).contains(SizeConstraint.MINIMUM_SIZE)) {
KVector minSize = node.getProperty(FixedLayouterOptions.NODE_SIZE_MINIMUM);
if (minSize.x > 0 && minSize.y > 0) {
ElkUtil.resizeNode(node, minSize.x, minSize.y, true, true);
}
}
}
maxx = Math.max(maxx, node.getX() + node.getWidth());
maxy = Math.max(maxy, node.getY() + node.getHeight());
// set the fixed position of the node labels, or leave them as they are
for (ElkLabel label : node.getLabels()) {
pos = label.getProperty(FixedLayouterOptions.POSITION);
if (pos != null) {
label.setLocation(pos.x, pos.y);
}
maxx = Math.max(maxx, node.getX() + label.getX() + label.getWidth());
maxy = Math.max(maxy, node.getY() + label.getY() + label.getHeight());
}
// set the fixed position of the ports, or leave them as they are
for (ElkPort port : node.getPorts()) {
pos = port.getProperty(FixedLayouterOptions.POSITION);
if (pos != null) {
port.setLocation(pos.x, pos.y);
}
double portx = node.getX() + port.getX();
double porty = node.getY() + port.getY();
maxx = Math.max(maxx, portx + port.getWidth());
maxy = Math.max(maxy, porty + port.getHeight());
// set the fixed position of the port labels, or leave them as they are
for (ElkLabel label : port.getLabels()) {
pos = label.getProperty(FixedLayouterOptions.POSITION);
if (pos != null) {
label.setLocation(pos.x, pos.y);
}
maxx = Math.max(maxx, portx + label.getX() + label.getWidth());
maxy = Math.max(maxy, porty + label.getY() + label.getHeight());
}
}
// set fixed routing for the node's outgoing edges (both simple and hierarchical), or leave them as they are
for (ElkEdge edge : ElkGraphUtil.allOutgoingEdges(node)) {
KVector maxv = processEdge(edge, edgeRouting);
maxx = Math.max(maxx, maxv.x);
maxy = Math.max(maxy, maxv.y);
}
// note that this potentially results in hierarchical edges being handled twice
for (ElkEdge edge : ElkGraphUtil.allIncomingEdges(node)) {
if (ElkGraphUtil.getSourceNode(edge).getParent() != layoutNode) {
KVector maxv = processEdge(edge, edgeRouting);
maxx = Math.max(maxx, maxv.x);
maxy = Math.max(maxy, maxv.y);
}
}
}
// if orthogonal routing is selected, determine the junction points
if (edgeRouting == EdgeRouting.ORTHOGONAL) {
for (ElkNode node : layoutNode.getChildren()) {
for (ElkEdge edge : ElkGraphUtil.allOutgoingEdges(node)) {
generateJunctionPoints(edge);
}
}
}
// set size of the parent node unless its size should be fixed as well
if (!layoutNode.getProperty(FixedLayouterOptions.NODE_SIZE_FIXED_GRAPH_SIZE)) {
ElkPadding padding = layoutNode.getProperty(FixedLayouterOptions.PADDING);
double newWidth = maxx + padding.getLeft() + padding.getRight();
double newHeight = maxy + padding.getTop() + padding.getBottom();
ElkUtil.resizeNode(layoutNode, newWidth, newHeight, true, true);
}
progressMonitor.done();
}
Aggregations