use of org.eclipse.elk.core.options.PortConstraints in project osate2 by osate.
the class ElkGraphBuilder method createElkPortsForElements.
/**
* Before calling this method, all labels for the parent node should have already been created and the node labels placement property must be set for the parent.
* @param elements
* @param parent
* @param mapping
*/
private void createElkPortsForElements(final Collection<DiagramElement> elements, final ElkNode parent, final LayoutMapping mapping) {
final EnumSet<NodeLabelPlacement> nodeLabelPlacement = parent.getProperty(CoreOptions.NODE_LABELS_PLACEMENT);
final boolean labelsAtTop = nodeLabelPlacement != null && nodeLabelPlacement.contains(NodeLabelPlacement.V_TOP);
final double topPadding = labelsAtTop ? parent.getLabels().stream().mapToDouble(l -> l.getY() + l.getHeight()).sum() : 0.0;
// Group children by the port side to which they should be assigned.
final List<DiagramElement> dockedShapes = elements.stream().filter(dockedShapeFilter).collect(Collectors.toList());
final boolean diagramElementIncludesNestedPorts = dockedShapes.stream().flatMap(de -> de.getChildren().stream()).anyMatch(dockedShapeFilter);
// Set the flag to indicate that there are nested ports which will not be included in the final layout graph
if (omitNestedPorts && diagramElementIncludesNestedPorts) {
mapping.getLayoutGraph().setProperty(AgeLayoutOptions.NESTED_PORTS_WERE_OMITTED, true);
}
// Set port constraints and graph hierarchy handling of the parent based on whether the diagram element actually has nested ports.
final boolean hasNestedPorts = !omitNestedPorts && diagramElementIncludesNestedPorts;
PortConstraints portConstraints;
if (dockedShapes.size() == 0) {
// Don't constrain ports if there aren't any. As of 2017-10-11, some other values can affect the layout even if the node does not contain ports.
portConstraints = PortConstraints.FREE;
} else {
if (hasNestedPorts || options.layoutPortsOnDefaultSides) {
portConstraints = PortConstraints.FIXED_POS;
} else {
portConstraints = PortConstraints.FREE;
}
}
parent.setProperty(CoreOptions.PORT_CONSTRAINTS, portConstraints);
final Map<PortSide, List<DiagramElement>> groupedDockedElements = dockedShapes.stream().collect(Collectors.groupingBy(de -> getPortSide(de, hasNestedPorts), HashMap::new, Collectors.toCollection(ArrayList::new)));
// Determine padding
// Need to pad both left and right sides equally if ELK is determining the side of ports. Otherwise, the space for the
// port may overlap with shapes. This is likely caused by adjusting the border offset of ports
// to lay out ports within the bounds of the containing shape
final boolean padOppositeSides = !portConstraints.isSideFixed();
final ElkPadding parentPadding = new ElkPadding(parent.getParent() == null || parent.getParent().getParent() == null ? 0.0 : portAndContentsPadding);
for (final Entry<PortSide, List<DiagramElement>> entry : groupedDockedElements.entrySet()) {
final PortSide side = entry.getKey();
double maxSize = 0;
for (final DiagramElement de : entry.getValue()) {
maxSize = Math.max(maxSize, getOrthogonalSize(de, side));
}
// Update padding for the side
final double sidePadding = maxSize + portAndContentsPadding;
switch(side) {
case NORTH:
parentPadding.top = Math.max(parentPadding.top, sidePadding);
break;
case SOUTH:
parentPadding.bottom = Math.max(parentPadding.bottom, sidePadding);
break;
case EAST:
parentPadding.right = Math.max(parentPadding.right, sidePadding);
if (padOppositeSides) {
parentPadding.left = Math.max(parentPadding.left, sidePadding);
}
break;
case WEST:
parentPadding.left = Math.max(parentPadding.left, sidePadding);
if (padOppositeSides) {
parentPadding.right = Math.max(parentPadding.right, sidePadding);
}
break;
default:
// Ignore
break;
}
}
// Create and position the ports
for (final Entry<PortSide, List<DiagramElement>> portSideToElementsEntry : groupedDockedElements.entrySet()) {
final PortSide side = portSideToElementsEntry.getKey();
final double additionalPadding;
if (PortSide.SIDES_NORTH_SOUTH.contains(side)) {
additionalPadding = Math.max(parentPadding.left, parentPadding.right);
} else {
additionalPadding = topPadding;
}
createAndPositionPorts(parent, portSideToElementsEntry.getValue(), portSideToElementsEntry.getKey(), additionalPadding, mapping, hasNestedPorts);
}
// Set the padding
parent.setProperty(CoreOptions.PADDING, parentPadding);
}
use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.
the class HierarchicalPortOrthogonalEdgeRouter method setNorthSouthDummyCoordinates.
// /////////////////////////////////////////////////////////////////////////////
// STEP 2: SET NORTH / SOUTH DUMMY COORDINATES
/**
* Set coordinates for northern and southern external port dummy nodes.
*
* @param layeredGraph the layered graph.
* @param northSouthDummies dummy nodes whose position to set.
*/
private void setNorthSouthDummyCoordinates(final LGraph layeredGraph, final List<LNode> northSouthDummies) {
PortConstraints constraints = layeredGraph.getProperty(LayeredOptions.PORT_CONSTRAINTS);
KVector graphSize = layeredGraph.getSize();
LPadding graphPadding = layeredGraph.getPadding();
double graphWidth = graphSize.x + graphPadding.left + graphPadding.right;
double northY = 0 - graphPadding.top - layeredGraph.getOffset().y;
double southY = graphSize.y + graphPadding.top + graphPadding.bottom - layeredGraph.getOffset().y;
// Lists of northern and southern external port dummies
List<LNode> northernDummies = Lists.newArrayList();
List<LNode> southernDummies = Lists.newArrayList();
for (LNode dummy : northSouthDummies) {
// Set x coordinate
switch(constraints) {
case FREE:
case FIXED_SIDE:
case FIXED_ORDER:
calculateNorthSouthDummyPositions(dummy);
break;
case FIXED_RATIO:
applyNorthSouthDummyRatio(dummy, graphWidth);
dummy.borderToContentAreaCoordinates(true, false);
break;
case FIXED_POS:
applyNorthSouthDummyPosition(dummy);
dummy.borderToContentAreaCoordinates(true, false);
// Ensure that the graph is wide enough to hold the port
graphSize.x = Math.max(graphSize.x, dummy.getPosition().x + dummy.getSize().x / 2.0);
break;
}
// Set y coordinates and add the dummy to its respective list
switch(dummy.getProperty(InternalProperties.EXT_PORT_SIDE)) {
case NORTH:
dummy.getPosition().y = northY;
northernDummies.add((dummy));
break;
case SOUTH:
dummy.getPosition().y = southY;
southernDummies.add(dummy);
break;
}
}
// have been put on top of one another
switch(constraints) {
case FREE:
case FIXED_SIDE:
ensureUniquePositions(northernDummies, layeredGraph);
ensureUniquePositions(southernDummies, layeredGraph);
break;
case FIXED_ORDER:
restoreProperOrder(northernDummies, layeredGraph);
restoreProperOrder(southernDummies, layeredGraph);
break;
}
}
use of org.eclipse.elk.core.options.PortConstraints 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.core.options.PortConstraints in project elk by eclipse.
the class ElkGraphImporter method transformExternalPort.
/**
* Transforms the given external port into a dummy node.
*
* @param elkgraph
* the original KGraph
* @param lgraph
* the corresponding layered graph
* @param elkport
* the port to be transformed
*/
private void transformExternalPort(final ElkNode elkgraph, final LGraph lgraph, final ElkPort elkport) {
// We need some information about the port
KVector elkportPosition = new KVector(elkport.getX() + elkport.getWidth() / 2.0, elkport.getY() + elkport.getHeight() / 2.0);
int netFlow = calculateNetFlow(elkport);
PortConstraints portConstraints = elkgraph.getProperty(LayeredOptions.PORT_CONSTRAINTS);
// If we don't have a proper port side, calculate one
PortSide portSide = elkport.getProperty(LayeredOptions.PORT_SIDE);
assert portSide != PortSide.UNDEFINED;
// If we don't have a port offset, infer one
if (!elkport.getAllProperties().containsKey(LayeredOptions.PORT_BORDER_OFFSET)) {
double portOffset;
// if port coordinates are (0,0), we default to port offset 0 to make the common case frustration-free
if (elkport.getX() == 0.0 && elkport.getY() == 0.0) {
portOffset = 0.0;
} else {
portOffset = ElkUtil.calcPortOffset(elkport, portSide);
}
elkport.setProperty(LayeredOptions.PORT_BORDER_OFFSET, portOffset);
}
// Create the external port dummy node
KVector graphSize = new KVector(elkgraph.getWidth(), elkgraph.getHeight());
LNode dummy = LGraphUtil.createExternalPortDummy(elkport, portConstraints, portSide, netFlow, graphSize, elkportPosition, new KVector(elkport.getWidth(), elkport.getHeight()), lgraph.getProperty(LayeredOptions.DIRECTION), lgraph);
dummy.setProperty(InternalProperties.ORIGIN, elkport);
// The dummy only has one port
LPort dummyPort = dummy.getPorts().get(0);
dummyPort.setConnectedToExternalNodes(isConnectedToExternalNodes(elkport));
dummy.setProperty(LayeredOptions.PORT_LABELS_PLACEMENT, PortLabelPlacement.outside());
// If the compound node wants to have its port labels placed on the inside, we need to leave
// enough space for them by creating an LLabel for the KLabels. If the compound node wants to
// have its port labels placed on the outside, we still need to leave enough space for them
// so the port placement does not cause problems on the outside, but we also don't want to waste
// space inside. Thus, for east and west ports, we reduce the label width to zero, otherwise
// we reduce the label height to zero
boolean insidePortLabels = elkgraph.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT).contains(PortLabelPlacement.INSIDE);
// Transform all of the port's labels
for (ElkLabel elklabel : elkport.getLabels()) {
if (!elklabel.getProperty(LayeredOptions.NO_LAYOUT) && !Strings.isNullOrEmpty(elklabel.getText())) {
LLabel llabel = transformLabel(elklabel);
dummyPort.getLabels().add(llabel);
// If the port labels are fixed, we should consider the part that is inside the node and not 0.
if (!insidePortLabels) {
double insidePart = 0;
if (PortLabelPlacement.isFixed(elkgraph.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT))) {
// We use 0 as port border offset here, as we only want the label part that is
// inside the node "after" the port.
insidePart = ElkUtil.computeInsidePart(new KVector(elklabel.getX(), elklabel.getY()), new KVector(elklabel.getWidth(), elklabel.getHeight()), new KVector(elkport.getWidth(), elkport.getHeight()), 0, portSide);
}
switch(portSide) {
case EAST:
case WEST:
llabel.getSize().x = insidePart;
break;
case NORTH:
case SOUTH:
llabel.getSize().y = insidePart;
break;
}
}
}
}
// Remember the relevant spacings that will apply to the labels here. It's not the spacings in the graph, but
// in the parent
dummy.setProperty(LayeredOptions.SPACING_LABEL_PORT, elkgraph.getParent().getProperty(LayeredOptions.SPACING_LABEL_PORT));
dummy.setProperty(LayeredOptions.SPACING_LABEL_LABEL, elkgraph.getParent().getProperty(LayeredOptions.SPACING_LABEL_LABEL));
// Put the external port dummy into our graph and associate it with the original KPort
lgraph.getLayerlessNodes().add(dummy);
nodeAndPortMap.put(elkport, dummy);
}
use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.
the class ElkGraphImporter method ensureDefinedPortSide.
/**
* Ensures that the given port has a defined port side.
*/
private void ensureDefinedPortSide(final LGraph lgraph, final ElkPort elkport) {
Direction layoutDirection = lgraph.getProperty(LayeredOptions.DIRECTION);
PortSide portSide = elkport.getProperty(LayeredOptions.PORT_SIDE);
PortConstraints portConstraints = lgraph.getProperty(LayeredOptions.PORT_CONSTRAINTS);
if (!portConstraints.isSideFixed()) {
// We are free to assign ports to sides, so the port side will depend on the layout direction and the
// port's net flow
int netFlow = calculateNetFlow(elkport);
if (netFlow > 0) {
portSide = PortSide.fromDirection(layoutDirection);
} else {
portSide = PortSide.fromDirection(layoutDirection).opposed();
}
} else {
// We are not free to assign port sides. If none is set, try inferring it from the port's position
if (portSide == PortSide.UNDEFINED) {
portSide = ElkUtil.calcPortSide(elkport, layoutDirection);
// There are cases where ELK may have failed to infer the port side
if (portSide == PortSide.UNDEFINED) {
portSide = PortSide.fromDirection(layoutDirection);
}
}
}
elkport.setProperty(LayeredOptions.PORT_SIDE, portSide);
}
Aggregations