use of org.eclipse.elk.graph.ElkPort in project elk by eclipse.
the class ElkGraphImporter method transformPort.
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Port Transformation
/**
* Transforms the given port. The new port will be added to the given node and will be
* registered with the {@code transformMap}.
*
* @param elkport
* the port to transform.
* @param parentLNode
* the node the port should be added to.
* @param graphProperties
* the graph properties of the graph the transformed port will be part of. The graph
* properties are modified depending on the port's properties.
* @param layoutDirection
* the layout direction in the graph the port will be part of.
* @param portConstraints
* the port constraints of the port's node.
* @return the transformed port.
*/
private LPort transformPort(final ElkPort elkport, final LNode parentLNode, final Set<GraphProperties> graphProperties, final Direction layoutDirection, final PortConstraints portConstraints) {
// create layered port, copying its position
LPort lport = new LPort();
lport.copyProperties(elkport);
lport.setSide(elkport.getProperty(LayeredOptions.PORT_SIDE));
lport.setProperty(InternalProperties.ORIGIN, elkport);
lport.setNode(parentLNode);
KVector portSize = lport.getSize();
portSize.x = elkport.getWidth();
portSize.y = elkport.getHeight();
KVector portPos = lport.getPosition();
portPos.x = elkport.getX();
portPos.y = elkport.getY();
nodeAndPortMap.put(elkport, lport);
// check if the original port has any outgoing connections to descendants of its node
boolean connectionsToDescendants = elkport.getOutgoingEdges().stream().flatMap(edge -> edge.getTargets().stream()).map(ElkGraphUtil::connectableShapeToNode).anyMatch(targetNode -> ElkGraphUtil.isDescendant(targetNode, elkport.getParent()));
// there could be yet incoming connections from descendants
if (!connectionsToDescendants) {
// check if the original port has any incoming connections from descendants of its node
connectionsToDescendants = elkport.getIncomingEdges().stream().flatMap(edge -> edge.getSources().stream()).map(ElkGraphUtil::connectableShapeToNode).anyMatch(sourceNode -> ElkGraphUtil.isDescendant(sourceNode, elkport.getParent()));
}
// if there are still no connections to descendants, there might yet be inside self loops involved
if (!connectionsToDescendants) {
// check if the original port has any incoming connections from descendants of its node
connectionsToDescendants = elkport.getOutgoingEdges().stream().anyMatch(edge -> edge.isSelfloop() && edge.getProperty(LayeredOptions.INSIDE_SELF_LOOPS_YO));
}
// if we have found connections to / from descendants, mark the port accordingly
lport.setProperty(InternalProperties.INSIDE_CONNECTIONS, connectionsToDescendants);
// initialize the port's side, offset, and anchor point
LGraphUtil.initializePort(lport, portConstraints, layoutDirection, elkport.getProperty(LayeredOptions.PORT_ANCHOR));
// create the port's labels
for (ElkLabel elklabel : elkport.getLabels()) {
if (!elklabel.getProperty(LayeredOptions.NO_LAYOUT) && !Strings.isNullOrEmpty(elklabel.getText())) {
lport.getLabels().add(transformLabel(elklabel));
}
}
switch(layoutDirection) {
case LEFT:
case RIGHT:
if (lport.getSide() == PortSide.NORTH || lport.getSide() == PortSide.SOUTH) {
graphProperties.add(GraphProperties.NORTH_SOUTH_PORTS);
}
break;
case UP:
case DOWN:
if (lport.getSide() == PortSide.EAST || lport.getSide() == PortSide.WEST) {
graphProperties.add(GraphProperties.NORTH_SOUTH_PORTS);
}
break;
}
return lport;
}
use of org.eclipse.elk.graph.ElkPort 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.graph.ElkPort in project elk by eclipse.
the class ElkGraphLayoutTransferrer method applyLayout.
/**
* Applies the layout information contained in the given LGraph to the ElkGraph elements it was
* created from. All source ElkGraph elements are expected to be accessible through their LGraph
* counterparts through the {@link InternalProperties#ORIGIN} property.
*
* @param lgraph the LGraph whose layout information to apply.
*/
public void applyLayout(final LGraph lgraph) {
Object graphOrigin = lgraph.getProperty(InternalProperties.ORIGIN);
if (!(graphOrigin instanceof ElkNode)) {
return;
}
// The ElkNode that represents this graph in the original ElkGraph
ElkNode parentElkNode = (ElkNode) graphOrigin;
// The LNode that represents this graph in the upper hierarchy level, if any
LNode parentLNode = (LNode) lgraph.getParentNode();
// Get the offset to be added to all coordinates
KVector offset = new KVector(lgraph.getOffset());
// Adjust offset (and with it the positions) by the requested padding
LPadding lPadding = lgraph.getPadding();
offset.x += lPadding.left;
offset.y += lPadding.top;
// Set node padding, if it was computed during layout
final EnumSet<SizeOptions> sizeOptions = parentElkNode.getProperty(LayeredOptions.NODE_SIZE_OPTIONS);
if (sizeOptions.contains(SizeOptions.COMPUTE_PADDING)) {
ElkPadding padding = parentElkNode.getProperty(LayeredOptions.PADDING);
padding.setBottom(lPadding.bottom);
padding.setTop(lPadding.top);
padding.setLeft(lPadding.left);
padding.setRight(lPadding.right);
}
// Along the way, we collect the list of edges to be processed later
List<LEdge> edgeList = Lists.newArrayList();
// Process the nodes
for (LNode lnode : lgraph.getLayerlessNodes()) {
if (representsNode(lnode)) {
applyNodeLayout(lnode, offset);
} else if (representsExternalPort(lnode) && parentLNode == null) {
// We have an external port here on the top-most hierarchy level of the current (possibly
// hierarchical) layout run; set its position
ElkPort elkport = (ElkPort) lnode.getProperty(InternalProperties.ORIGIN);
KVector portPosition = LGraphUtil.getExternalPortPosition(lgraph, lnode, elkport.getWidth(), elkport.getHeight());
elkport.setLocation(portPosition.x, portPosition.y);
}
// correctly)
for (LPort port : lnode.getPorts()) {
port.getOutgoingEdges().stream().filter(edge -> !LGraphUtil.isDescendant(edge.getTarget().getNode(), lnode)).forEach(edge -> edgeList.add(edge));
}
}
// Collect edges that go from the current graph's representing LNode down into its descendants
if (parentLNode != null) {
for (LPort port : parentLNode.getPorts()) {
port.getOutgoingEdges().stream().filter(edge -> LGraphUtil.isDescendant(edge.getTarget().getNode(), parentLNode)).forEach(edge -> edgeList.add(edge));
}
}
// Iterate through all edges
EdgeRouting routing = parentElkNode.getProperty(LayeredOptions.EDGE_ROUTING);
for (LEdge ledge : edgeList) {
applyEdgeLayout(ledge, routing, offset, lPadding);
}
// Setup the parent node
applyParentNodeLayout(lgraph);
// Process nested subgraphs
for (LNode lnode : lgraph.getLayerlessNodes()) {
LGraph nestedGraph = lnode.getNestedGraph();
if (nestedGraph != null) {
applyLayout(nestedGraph);
}
}
}
use of org.eclipse.elk.graph.ElkPort in project elk by eclipse.
the class RandomGraphGenerator method distributePorts.
/**
* Distribute all ports on the border of the given node.
*
* @param node
* a node
*/
private void distributePorts(final ElkNode node) {
// count the ports on each side of the node
int northCount = 0, eastCount = 0, southCount = 0, westCount = 0;
for (ElkPort port : node.getPorts()) {
switch(port.getProperty(CoreOptions.PORT_SIDE)) {
case NORTH:
northCount++;
break;
case EAST:
eastCount++;
break;
case SOUTH:
southCount++;
break;
case WEST:
westCount++;
break;
}
}
// make sure the node is big enough to contain all ports
float portWidth = get(GeneratorOptions.PORT_WIDTH).floatVal(random);
float portHeight = get(GeneratorOptions.PORT_HEIGHT).floatVal(random);
if (node.getWidth() < (northCount + 1) * (portWidth + PORT_SEPARATION)) {
node.setWidth((northCount + 1) * (portWidth + PORT_SEPARATION));
}
if (node.getWidth() < (southCount + 1) * (portWidth + PORT_SEPARATION)) {
node.setWidth((southCount + 1) * (portWidth + PORT_SEPARATION));
}
if (node.getHeight() < (eastCount + 1) * (portHeight + PORT_SEPARATION)) {
node.setHeight((eastCount + 1) * (portHeight + PORT_SEPARATION));
}
if (node.getHeight() < (westCount + 1) * (portHeight + PORT_SEPARATION)) {
node.setHeight((westCount + 1) * (portHeight + PORT_SEPARATION));
}
// distribute the ports on each node side
double northDelta = node.getWidth() / (northCount + 1);
double eastDelta = node.getHeight() / (eastCount + 1);
double southDelta = node.getWidth() / (southCount + 1);
double westDelta = node.getHeight() / (westCount + 1);
double northPos = 0, eastPos = 0, southPos = 0, westPos = 0;
for (ElkPort port : node.getPorts()) {
switch(port.getProperty(CoreOptions.PORT_SIDE)) {
case NORTH:
northPos += northDelta;
port.setLocation(northPos - port.getWidth() / 2, -port.getHeight());
break;
case EAST:
eastPos += eastDelta;
port.setLocation(node.getWidth(), eastPos - port.getHeight() / 2);
break;
case SOUTH:
southPos += southDelta;
port.setLocation(southPos - port.getWidth() / 2, node.getHeight());
break;
case WEST:
westPos += westDelta;
port.setLocation(-port.getWidth(), westPos - port.getHeight() / 2);
break;
}
}
}
use of org.eclipse.elk.graph.ElkPort in project elk by eclipse.
the class RandomGraphGenerator method moveTarget.
/**
* Changes the target of a given edge to a given node.
*
* @param edge
* the edge
* @param node
* the new target node
*/
private void moveTarget(final ElkEdge edge, final ElkConnectableShape oldConnectShape, final ElkConnectableShape newConnectShape) {
ElkPort port = null;
ElkNode oldNode = null;
ElkNode newNode = null;
ElkPort oldPort = null;
ElkPort newPort = null;
if (get(GeneratorOptions.ENABLE_PORTS)) {
// }
if (!edge.getTargets().isEmpty()) {
if (oldConnectShape instanceof ElkNodeImpl) {
oldNode = (ElkNode) oldConnectShape;
for (ElkConnectableShape target : edge.getTargets()) {
if (target instanceof ElkPortImpl) {
port = (ElkPortImpl) target;
if (port.getParent().equals(oldNode)) {
edge.getTargets().remove(port);
if (port.getOutgoingEdges().size() == 0 && port.getIncomingEdges().size() == 1) {
port.getParent().getPorts().remove(port);
}
}
}
}
} else if (oldConnectShape instanceof ElkPortImpl) {
oldPort = (ElkPort) oldConnectShape;
if (edge.getTargets().contains(oldPort)) {
edge.getTargets().remove(oldPort);
}
if (oldPort.getOutgoingEdges().size() == 0 && oldPort.getIncomingEdges().size() == 1) {
oldPort.getParent().getPorts().remove(oldPort);
}
}
}
if (newConnectShape instanceof ElkNodeImpl) {
newNode = (ElkNode) oldConnectShape;
newPort = retrievePort(newNode, true);
} else if (newConnectShape instanceof ElkPortImpl) {
newPort = (ElkPort) oldConnectShape;
}
if (!isHypernode(newNode)) {
// edge.setSourcePort(newPort);
edge.getTargets().add(newPort);
}
} else {
// edge.setSource(node);
if (oldConnectShape instanceof ElkNodeImpl) {
oldNode = (ElkNode) oldConnectShape;
} else if (oldConnectShape instanceof ElkPortImpl) {
oldPort = (ElkPort) oldConnectShape;
oldNode = oldPort.getParent();
}
if (edge.getTargets().contains(oldNode)) {
edge.getTargets().remove(oldNode);
}
if (newConnectShape instanceof ElkNodeImpl) {
newNode = (ElkNode) newConnectShape;
} else if (newConnectShape instanceof ElkPortImpl) {
newPort = (ElkPort) newConnectShape;
newNode = newPort.getParent();
}
edge.getTargets().add(newNode);
}
ElkGraphUtil.updateContainment(edge);
}
Aggregations