use of org.eclipse.elk.graph.ElkLabel 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.ElkLabel in project elk by eclipse.
the class ElkUtil method ensureLabel.
/**
* If the element does not already own a label, a label is created based on the element's
* identifier.
*/
private static void ensureLabel(final ElkGraphElement klge) {
if (klge.getLabels().isEmpty()) {
if (!Strings.isNullOrEmpty(klge.getIdentifier())) {
ElkLabel label = ElkGraphUtil.createLabel(klge);
label.setText(klge.getIdentifier());
}
}
}
use of org.eclipse.elk.graph.ElkLabel in project elk by eclipse.
the class ElkUtil method applyConfiguredNodeScaling.
/**
* Applies the scaling factor configured in terms of {@link CoreOptions#SCALE_FACTOR} to {@code node}'s
* size data, and updates the layout data of {@code node}'s ports and labels accordingly.<br>
* <b>Note:</b> The scaled layout data won't be reverted during the layout process, see
* {@link CoreOptions#SCALE_FACTOR}.
*
* @param node
* the node to be scaled
*/
public static void applyConfiguredNodeScaling(final ElkNode node) {
final double scalingFactor = node.getProperty(CoreOptions.SCALE_FACTOR);
if (scalingFactor == 1) {
return;
}
node.setDimensions(scalingFactor * node.getWidth(), scalingFactor * node.getHeight());
final Iterable<ElkLabel> portLabels = Iterables.concat(Iterables.transform(node.getPorts(), p -> p.getLabels()));
for (ElkShape shape : Iterables.concat(node.getLabels(), node.getPorts(), portLabels)) {
shape.setLocation(scalingFactor * shape.getX(), scalingFactor * shape.getY());
shape.setDimensions(scalingFactor * shape.getWidth(), scalingFactor * shape.getHeight());
final KVector anchor = shape.getProperty(CoreOptions.PORT_ANCHOR);
if (anchor != null) {
anchor.x *= scalingFactor;
anchor.y *= scalingFactor;
}
}
}
use of org.eclipse.elk.graph.ElkLabel in project elk by eclipse.
the class ElkUtil method resizeNode.
/**
* Resize a node to the given width and height, adjusting port and label positions if needed.
*
* @param node a node
* @param newWidth the new width to set
* @param newHeight the new height to set
* @param movePorts whether port positions should be adjusted
* @param moveLabels whether label positions should be adjusted
* @return a vector holding the width and height resizing ratio
*/
public static KVector resizeNode(final ElkNode node, final double newWidth, final double newHeight, final boolean movePorts, final boolean moveLabels) {
KVector oldSize = new KVector(node.getWidth(), node.getHeight());
KVector newSize = effectiveMinSizeConstraintFor(node);
newSize.x = Math.max(newSize.x, newWidth);
newSize.y = Math.max(newSize.y, newHeight);
double widthRatio = newSize.x / oldSize.x;
double heightRatio = newSize.y / oldSize.y;
double widthDiff = newSize.x - oldSize.x;
double heightDiff = newSize.y - oldSize.y;
// update port positions
if (movePorts) {
Direction direction = node.getParent() == null ? node.getProperty(CoreOptions.DIRECTION) : node.getParent().getProperty(CoreOptions.DIRECTION);
boolean fixedPorts = node.getProperty(CoreOptions.PORT_CONSTRAINTS) == PortConstraints.FIXED_POS;
for (ElkPort port : node.getPorts()) {
PortSide portSide = port.getProperty(CoreOptions.PORT_SIDE);
if (portSide == PortSide.UNDEFINED) {
portSide = calcPortSide(port, direction);
port.setProperty(CoreOptions.PORT_SIDE, portSide);
}
switch(portSide) {
case NORTH:
if (!fixedPorts) {
port.setX(port.getX() * widthRatio);
}
break;
case EAST:
port.setX(port.getX() + widthDiff);
if (!fixedPorts) {
port.setY(port.getY() * heightRatio);
}
break;
case SOUTH:
if (!fixedPorts) {
port.setX(port.getX() * widthRatio);
}
port.setY(port.getY() + heightDiff);
break;
case WEST:
if (!fixedPorts) {
port.setY(port.getY() * heightRatio);
}
break;
}
}
}
// resize the node AFTER ports have been placed, since calcPortSide needs the old size
node.setDimensions(newSize.x, newSize.y);
// update label positions
if (moveLabels) {
for (ElkLabel label : node.getLabels()) {
double midx = label.getX() + label.getWidth() / 2;
double midy = label.getY() + label.getHeight() / 2;
double widthPercent = midx / oldSize.x;
double heightPercent = midy / oldSize.y;
if (widthPercent + heightPercent >= 1) {
if (widthPercent - heightPercent > 0 && midy >= 0) {
// label is on the right
label.setX(label.getX() + widthDiff);
label.setY(label.getY() + heightDiff * heightPercent);
} else if (widthPercent - heightPercent < 0 && midx >= 0) {
// label is on the bottom
label.setX(label.getX() + widthDiff * widthPercent);
label.setY(label.getY() + heightDiff);
}
}
}
}
// set fixed size option for the node: now the size is assumed to stay as determined here
node.setProperty(CoreOptions.NODE_SIZE_CONSTRAINTS, SizeConstraint.fixed());
return new KVector(widthRatio, heightRatio);
}
use of org.eclipse.elk.graph.ElkLabel 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(")");
}
}
}
Aggregations