use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.
the class HierarchicalPortPositionProcessor method fixCoordinates.
/**
* Fixes the y coordinates of external port dummies in the given layer.
*
* @param layer the layer.
* @param layeredGraph the layered graph.
* @param portConstraints the port constraints that apply to external ports.
* @param graphHeight height of the graph.
*/
private void fixCoordinates(final Layer layer, final LGraph layeredGraph) {
PortConstraints portConstraints = layeredGraph.getProperty(LayeredOptions.PORT_CONSTRAINTS);
if (!(portConstraints.isRatioFixed() || portConstraints.isPosFixed())) {
// If coordinates are free to be set, we're done
return;
}
double graphHeight = layeredGraph.getActualSize().y;
// Iterate over the layer's nodes
for (LNode node : layer) {
// We only care about external port dummies...
if (node.getType() != NodeType.EXTERNAL_PORT) {
continue;
}
// ...representing eastern or western ports.
PortSide extPortSide = node.getProperty(InternalProperties.EXT_PORT_SIDE);
if (extPortSide != PortSide.EAST && extPortSide != PortSide.WEST) {
continue;
}
double finalYCoordinate = node.getProperty(InternalProperties.PORT_RATIO_OR_POSITION);
if (portConstraints == PortConstraints.FIXED_RATIO) {
// finalYCoordinate is a ratio that must be multiplied with the graph's height
finalYCoordinate *= graphHeight;
}
// Apply the node's new Y coordinate
node.getPosition().y = finalYCoordinate - node.getProperty(LayeredOptions.PORT_ANCHOR).y;
node.borderToContentAreaCoordinates(false, true);
}
}
use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.
the class HierarchicalPortConstraintProcessor method processNorthernAndSouthernPortDummies.
// /////////////////////////////////////////////////////////////////////////////
// North / South Hierarchical Port Dummies
/**
* Process northern and southern hierarchical port dummies.
*
* @param layeredGraph the layered graph.
*/
private void processNorthernAndSouthernPortDummies(final LGraph layeredGraph) {
// If the port constraints are not at least FIXED_SIDE, there's nothing to do here
PortConstraints portConstraints = layeredGraph.getProperty(LayeredOptions.PORT_CONSTRAINTS);
if (!portConstraints.isSideFixed()) {
return;
}
List<Layer> layers = layeredGraph.getLayers();
int layerCount = layers.size();
// For each layer, we keep a map of dummy nodes created for a given original external port
// dummy. This lets us remember which new dummy node was created for which original external
// port dummy in which layer. We also keep a list of dummy nodes to be added to each layer
// since iterating over the new dummy nodes in the map may mess up their order since we don't
// have hashCode() implemented. Once we do, this code can be reworked to just use the maps
// again.
// We keep enough space to hold layerCount + 2 instances of each data structure because we
// might have to add a new first and last layer, even though that shouldn't normally happen
List<Map<Object, LNode>> extPortToDummyNodeMap = Lists.newArrayListWithExpectedSize(layerCount + 2);
List<List<LNode>> newDummyNodes = Lists.newArrayListWithExpectedSize(layerCount + 2);
// Add maps and lists for a new first layer that might have to be created as well as for the
// current first layer. A map for the next layer is added on each iteration of the for loop
extPortToDummyNodeMap.add(new HashMap<Object, LNode>());
extPortToDummyNodeMap.add(new HashMap<Object, LNode>());
newDummyNodes.add(new ArrayList<LNode>());
newDummyNodes.add(new ArrayList<LNode>());
// We remember each original external port dummy we encounter (they must be removed from the layers later)
List<LNode> originalExternalPortDummies = Lists.newArrayList();
// Iterate through each layer
for (int currLayerIdx = 0; currLayerIdx < layerCount; currLayerIdx++) {
Layer currentLayer = layers.get(currLayerIdx);
// Dummy node maps and lists for the next and previous layer
Map<Object, LNode> prevExtPortToDummyNodesMap = extPortToDummyNodeMap.get(currLayerIdx);
Map<Object, LNode> nextExtPortToDummyNodesMap = Maps.newHashMap();
extPortToDummyNodeMap.add(nextExtPortToDummyNodesMap);
List<LNode> prevNewDummyNodes = newDummyNodes.get(currLayerIdx);
List<LNode> nextNewDummyNodes = Lists.newArrayList();
newDummyNodes.add(nextNewDummyNodes);
// northern / southern hierarchical port dummies
for (LNode currentNode : currentLayer) {
if (isNorthernOrSouthernDummy(currentNode)) {
// It's a northern or southern external port dummy. Schedule for removal and move on to next node
originalExternalPortDummies.add(currentNode);
continue;
}
// Iterate over the node's incoming edges
for (LEdge edge : currentNode.getIncomingEdges()) {
LNode sourceNode = edge.getSource().getNode();
// Check if it's a northern / southern dummy node
if (!isNorthernOrSouthernDummy(sourceNode)) {
continue;
}
// See if a dummy has already been created for the previous layer
LNode prevLayerDummy = prevExtPortToDummyNodesMap.get(sourceNode.getProperty(InternalProperties.ORIGIN));
if (prevLayerDummy == null) {
// No. Create one.
prevLayerDummy = createDummy(layeredGraph, sourceNode);
prevExtPortToDummyNodesMap.put(sourceNode.getProperty(InternalProperties.ORIGIN), prevLayerDummy);
prevNewDummyNodes.add(prevLayerDummy);
}
// Reroute the edge
edge.setSource(prevLayerDummy.getPorts().get(DUMMY_OUTPUT_PORT));
}
// Iterate over the node's outgoing edges
for (LEdge edge : currentNode.getOutgoingEdges()) {
LNode targetNode = edge.getTarget().getNode();
// Check if it's a northern / southern dummy node
if (!isNorthernOrSouthernDummy(targetNode)) {
continue;
}
// See if a dummy has already been created for the next layer
LNode nextLayerDummy = nextExtPortToDummyNodesMap.get(targetNode.getProperty(InternalProperties.ORIGIN));
if (nextLayerDummy == null) {
// No. Create one.
nextLayerDummy = createDummy(layeredGraph, targetNode);
nextExtPortToDummyNodesMap.put(targetNode.getProperty(InternalProperties.ORIGIN), nextLayerDummy);
nextNewDummyNodes.add(nextLayerDummy);
}
// Reroute the edge
edge.setTarget(nextLayerDummy.getPorts().get(DUMMY_INPUT_PORT));
}
}
}
// Add the newly created dummy nodes
for (int i = 0; i < newDummyNodes.size(); i++) {
List<LNode> nodeList = newDummyNodes.get(i);
if (nodeList.isEmpty()) {
// No dummy nodes, so just move on
continue;
}
// Find the layer the dummy nodes should be added to
Layer layer = null;
if (i == 0) {
// A new first layer must be created
layer = new Layer(layeredGraph);
layers.add(0, layer);
} else if (i == extPortToDummyNodeMap.size() - 1) {
// A new layer layer must be created
layer = new Layer(layeredGraph);
layers.add(layer);
} else {
layer = layers.get(i - 1);
}
for (LNode dummy : nodeList) {
dummy.setLayer(layer);
}
}
// Iterate through the hierarchical port dummies and remove them
for (LNode originalDummy : originalExternalPortDummies) {
// Remove the original dummy; new dummy nodes have already been created for it
originalDummy.setLayer(null);
}
// Remember the original external port dummies in the graph
layeredGraph.setProperty(InternalProperties.EXT_PORT_REPLACED_DUMMIES, originalExternalPortDummies);
}
use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.
the class CompoundGraphPreprocessor method transformHierarchyEdges.
/**
* Recursively transform cross-hierarchy edges into sequences of dummy ports and dummy edges.
*
* @param graph
* the layered graph to process
* @param parentNode
* the node that represents the graph in the upper hierarchy level, or {@code null}
* if it already is on top-level
* @return the external ports created to split edges that cross the boundary of the parent node
*/
private List<ExternalPort> transformHierarchyEdges(final LGraph graph, final LNode parentNode) {
// process all children and recurse down to gather their external ports
List<ExternalPort> containedExternalPorts = Lists.newArrayList();
for (LNode node : graph.getLayerlessNodes()) {
LGraph nestedGraph = node.getNestedGraph();
if (nestedGraph != null) {
// recursively process the child graph
List<ExternalPort> childPorts = transformHierarchyEdges(nestedGraph, node);
containedExternalPorts.addAll(childPorts);
// process inside self loops
processInsideSelfLoops(nestedGraph, node);
// will already have been created, but perhaps not all)
if (nestedGraph.getProperty(InternalProperties.GRAPH_PROPERTIES).contains(GraphProperties.EXTERNAL_PORTS)) {
// We need the port constraints to position external ports (Issues KIPRA-1528, ELK-48)
PortConstraints portConstraints = node.getProperty(LayeredOptions.PORT_CONSTRAINTS);
boolean insidePortLabels = node.getProperty(LayeredOptions.PORT_LABELS_PLACEMENT).contains(PortLabelPlacement.INSIDE);
for (LPort port : node.getPorts()) {
// Make sure that every port has a dummy node created for it
LNode dummyNode = dummyNodeMap.get(port);
if (dummyNode == null) {
dummyNode = LGraphUtil.createExternalPortDummy(port, portConstraints, port.getSide(), -port.getNetFlow(), null, new KVector(), port.getSize(), nestedGraph.getProperty(LayeredOptions.DIRECTION), nestedGraph);
dummyNode.setProperty(InternalProperties.ORIGIN, port);
dummyNodeMap.put(port, dummyNode);
nestedGraph.getLayerlessNodes().add(dummyNode);
}
// We need to reserve space for external port labels by adding those labels to our dummy nodes
LPort dummyNodePort = dummyNode.getPorts().get(0);
for (LLabel extPortLabel : port.getLabels()) {
LLabel dummyPortLabel = new LLabel();
dummyPortLabel.getSize().x = extPortLabel.getSize().x;
dummyPortLabel.getSize().y = extPortLabel.getSize().y;
dummyNodePort.getLabels().add(dummyPortLabel);
// But if the port labels are fixed, we should consider the part that is inside the node.
if (!insidePortLabels) {
PortSide side = port.getSide();
double insidePart = 0;
if (PortLabelPlacement.isFixed(node.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(extPortLabel.getPosition(), extPortLabel.getSize(), port.getSize(), 0, side);
}
if (portConstraints == PortConstraints.FREE || PortSide.SIDES_EAST_WEST.contains(side)) {
dummyPortLabel.getSize().x = insidePart;
} else {
dummyPortLabel.getSize().y = insidePart;
}
}
}
}
}
}
}
// this will be the list of external ports we will export
List<ExternalPort> exportedExternalPorts = Lists.newArrayList();
// process the cross-hierarchy edges connected to the inside of the child nodes
processInnerHierarchicalEdgeSegments(graph, parentNode, containedExternalPorts, exportedExternalPorts);
// process the cross-hierarchy edges connected to the outside of the parent node
if (parentNode != null) {
processOuterHierarchicalEdgeSegments(graph, parentNode, exportedExternalPorts);
}
return exportedExternalPorts;
}
use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.
the class LGraphUtil method computeGraphProperties.
// /////////////////////////////////////////////////////////////////////////////
// Graph Properties
/**
* Compute the graph properties of the given layered graph. These properties are important
* to determine which intermediate processors are included in the layout run.
* Ideally the properties are computed during the import of the source format into {@link LGraph},
* e.g. as done in {@code KGraphImporter}. This method is offered only for convenience.
* <p>
* The nodes are expected to be in the {@link LGraph#getLayerlessNodes()} list.
* </p>
*
* @param layeredGraph a layered graph
*/
public static void computeGraphProperties(final LGraph layeredGraph) {
Set<GraphProperties> props = layeredGraph.getProperty(InternalProperties.GRAPH_PROPERTIES);
if (!props.isEmpty()) {
props.clear();
}
Direction direction = getDirection(layeredGraph);
for (LNode node : layeredGraph.getLayerlessNodes()) {
if (node.getProperty(LayeredOptions.COMMENT_BOX)) {
props.add(GraphProperties.COMMENTS);
} else if (node.getProperty(LayeredOptions.HYPERNODE)) {
props.add(GraphProperties.HYPERNODES);
props.add(GraphProperties.HYPEREDGES);
} else if (node.getType() == NodeType.EXTERNAL_PORT) {
props.add(GraphProperties.EXTERNAL_PORTS);
}
PortConstraints portConstraints = node.getProperty(LayeredOptions.PORT_CONSTRAINTS);
if (portConstraints == PortConstraints.UNDEFINED) {
// correct the port constraints value
node.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FREE);
} else if (portConstraints != PortConstraints.FREE) {
props.add(GraphProperties.NON_FREE_PORTS);
}
for (LPort port : node.getPorts()) {
if (port.getIncomingEdges().size() + port.getOutgoingEdges().size() > 1) {
props.add(GraphProperties.HYPEREDGES);
}
PortSide portSide = port.getSide();
switch(direction) {
case UP:
case DOWN:
if (portSide == PortSide.EAST || portSide == PortSide.WEST) {
props.add(GraphProperties.NORTH_SOUTH_PORTS);
}
break;
default:
if (portSide == PortSide.NORTH || portSide == PortSide.SOUTH) {
props.add(GraphProperties.NORTH_SOUTH_PORTS);
}
}
for (LEdge edge : port.getOutgoingEdges()) {
if (edge.getTarget().getNode() == node) {
props.add(GraphProperties.SELF_LOOPS);
}
for (LLabel label : edge.getLabels()) {
switch(label.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT)) {
case CENTER:
props.add(GraphProperties.CENTER_LABELS);
break;
case HEAD:
case TAIL:
props.add(GraphProperties.END_LABELS);
break;
}
}
}
}
}
}
use of org.eclipse.elk.core.options.PortConstraints in project elk by eclipse.
the class GraphConfigurator method copyPortConstraints.
private void copyPortConstraints(final LNode node) {
PortConstraints originalPortconstraints = node.getProperty(LayeredOptions.PORT_CONSTRAINTS);
node.setProperty(InternalProperties.ORIGINAL_PORT_CONSTRAINTS, originalPortconstraints);
LGraph nestedGraph = node.getNestedGraph();
if (nestedGraph != null) {
copyPortContraints(nestedGraph);
}
}
Aggregations