Search in sources :

Example 1 with AtomicCell

use of org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell in project elk by eclipse.

the class PortPlacementCalculator method placeVerticalFreePorts.

/**
 * Places ports on the eastern and western side for the unconstrained cases.
 */
private static void placeVerticalFreePorts(final NodeContext nodeContext, final PortSide portSide) {
    // If there are no ports on the given side, abort
    if (nodeContext.portContexts.get(portSide).isEmpty()) {
        return;
    }
    // Retrieve the proper inside port label cell, which will give us hints as to where to place our ports
    AtomicCell insidePortLabelCell = nodeContext.insidePortLabelCells.get(portSide);
    ElkRectangle insidePortLabelCellRectangle = insidePortLabelCell.getCellRectangle();
    ElkPadding insidePortLabelCellPadding = insidePortLabelCell.getPadding();
    // Note that we don't have to distinguish any cases here because the port margins already include space
    // required for labels, if such space is to be reserved. Yay!
    PortAlignment portAlignment = nodeContext.getPortAlignment(portSide);
    double availableSpace = insidePortLabelCellRectangle.height - insidePortLabelCellPadding.top - insidePortLabelCellPadding.bottom;
    double calculatedPortPlacementHeight = insidePortLabelCell.getMinimumContentAreaSize().y;
    double currentYPos = insidePortLabelCellRectangle.y + insidePortLabelCellPadding.top;
    double spaceBetweenPorts = nodeContext.portPortSpacing;
    double nodeWidth = nodeContext.nodeSize.x;
    // to center to keep things from looking stupid
    if ((portAlignment == PortAlignment.DISTRIBUTED || portAlignment == PortAlignment.JUSTIFIED) && nodeContext.portContexts.get(portSide).size() == 1) {
        calculatedPortPlacementHeight = modifiedPortPlacementSize(nodeContext, portAlignment, calculatedPortPlacementHeight);
        portAlignment = PortAlignment.CENTER;
    }
    if (availableSpace < calculatedPortPlacementHeight && !nodeContext.sizeOptions.contains(SizeOptions.PORTS_OVERHANG)) {
        // the space between them to cram them into the available space.
        if (portAlignment == PortAlignment.DISTRIBUTED) {
            spaceBetweenPorts += (availableSpace - calculatedPortPlacementHeight) / (nodeContext.portContexts.get(portSide).size() + 1);
            currentYPos += spaceBetweenPorts;
        } else {
            spaceBetweenPorts += (availableSpace - calculatedPortPlacementHeight) / (nodeContext.portContexts.get(portSide).size() - 1);
        }
    } else {
        // case where we should fall back to centered alignment
        if (availableSpace < calculatedPortPlacementHeight) {
            calculatedPortPlacementHeight = modifiedPortPlacementSize(nodeContext, portAlignment, calculatedPortPlacementHeight);
            portAlignment = PortAlignment.CENTER;
        }
        // otherwise expect)
        switch(portAlignment) {
            case BEGIN:
                // There's nothing to do here
                break;
            case CENTER:
                currentYPos += (availableSpace - calculatedPortPlacementHeight) / 2;
                break;
            case END:
                currentYPos += availableSpace - calculatedPortPlacementHeight;
                break;
            case DISTRIBUTED:
                // In this case, if there is not enough space available to place the ports, we are allowed to overhang.
                // We thus need to ensure that we're only ever increasing the port spacing here
                double additionalSpaceBetweenPorts = (availableSpace - calculatedPortPlacementHeight) / (nodeContext.portContexts.get(portSide).size() + 1);
                spaceBetweenPorts += Math.max(0, additionalSpaceBetweenPorts);
                currentYPos += spaceBetweenPorts;
                break;
            case JUSTIFIED:
                // In this case, if there is not enough space available to place the ports, we are allowed to overhang.
                // We thus need to ensure that we're only ever increasing the port spacing here
                additionalSpaceBetweenPorts = (availableSpace - calculatedPortPlacementHeight) / (nodeContext.portContexts.get(portSide).size() - 1);
                spaceBetweenPorts += Math.max(0, additionalSpaceBetweenPorts);
                break;
        }
    }
    // Iterate over all ports and place them
    for (PortContext portContext : nodeContext.portContexts.get(portSide)) {
        portContext.portPosition.x = calculateVerticalPortXCoordinate(portContext, nodeWidth);
        portContext.portPosition.y = currentYPos + portContext.portMargin.top;
        // Update the y coordinate for the next port
        currentYPos += portContext.portMargin.top + portContext.port.getSize().y + portContext.portMargin.bottom + spaceBetweenPorts;
    }
}
Also used : PortAlignment(org.eclipse.elk.core.options.PortAlignment) AtomicCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle) ElkPadding(org.eclipse.elk.core.math.ElkPadding) PortContext(org.eclipse.elk.alg.common.nodespacing.internal.PortContext)

Example 2 with AtomicCell

use of org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell in project elk by eclipse.

the class PortPlacementCalculator method placeHorizontalFreePorts.

/**
 * Places ports on the northern and southern side for the unconstrained cases.
 */
private static void placeHorizontalFreePorts(final NodeContext nodeContext, final PortSide portSide) {
    // If there are no ports on the given side, abort
    if (nodeContext.portContexts.get(portSide).isEmpty()) {
        return;
    }
    // Retrieve the proper inside port label cell, which will give us hints as to where to place our ports
    AtomicCell insidePortLabelCell = nodeContext.insidePortLabelCells.get(portSide);
    ElkRectangle insidePortLabelCellRectangle = insidePortLabelCell.getCellRectangle();
    ElkPadding insidePortLabelCellPadding = insidePortLabelCell.getPadding();
    // Note that we don't have to distinguish any cases here because the port margins already include space
    // required for labels, if such space is to be reserved. Yay!
    PortAlignment portAlignment = nodeContext.getPortAlignment(portSide);
    double availableSpace = insidePortLabelCellRectangle.width - insidePortLabelCellPadding.left - insidePortLabelCellPadding.right;
    double calculatedPortPlacementWidth = insidePortLabelCell.getMinimumContentAreaSize().x;
    double currentXPos = insidePortLabelCellRectangle.x + insidePortLabelCellPadding.left;
    double spaceBetweenPorts = nodeContext.portPortSpacing;
    // to center to keep things from looking stupid
    if ((portAlignment == PortAlignment.DISTRIBUTED || portAlignment == PortAlignment.JUSTIFIED) && nodeContext.portContexts.get(portSide).size() == 1) {
        calculatedPortPlacementWidth = modifiedPortPlacementSize(nodeContext, portAlignment, calculatedPortPlacementWidth);
        portAlignment = PortAlignment.CENTER;
    }
    if (availableSpace < calculatedPortPlacementWidth && !nodeContext.sizeOptions.contains(SizeOptions.PORTS_OVERHANG)) {
        // the space between them to cram them into the available space.
        if (portAlignment == PortAlignment.DISTRIBUTED) {
            spaceBetweenPorts += (availableSpace - calculatedPortPlacementWidth) / (nodeContext.portContexts.get(portSide).size() + 1);
            currentXPos += spaceBetweenPorts;
        } else {
            spaceBetweenPorts += (availableSpace - calculatedPortPlacementWidth) / (nodeContext.portContexts.get(portSide).size() - 1);
        }
    } else {
        // case where we should fall back to centered alignment
        if (availableSpace < calculatedPortPlacementWidth) {
            calculatedPortPlacementWidth = modifiedPortPlacementSize(nodeContext, portAlignment, calculatedPortPlacementWidth);
            portAlignment = PortAlignment.CENTER;
        }
        // otherwise expect)
        switch(portAlignment) {
            case BEGIN:
                // There's nothing to do here
                break;
            case CENTER:
                currentXPos += (availableSpace - calculatedPortPlacementWidth) / 2;
                break;
            case END:
                currentXPos += availableSpace - calculatedPortPlacementWidth;
                break;
            case DISTRIBUTED:
                // In this case, if there is not enough space available to place the ports, we are allowed to overhang.
                // We thus need to ensure that we're only ever increasing the port spacing here
                double additionalSpaceBetweenPorts = (availableSpace - calculatedPortPlacementWidth) / (nodeContext.portContexts.get(portSide).size() + 1);
                spaceBetweenPorts += Math.max(0, additionalSpaceBetweenPorts);
                currentXPos += spaceBetweenPorts;
                break;
            case JUSTIFIED:
                // In this case, if there is not enough space available to place the ports, we are allowed to overhang.
                // We thus need to ensure that we're only ever increasing the port spacing here
                additionalSpaceBetweenPorts = (availableSpace - calculatedPortPlacementWidth) / (nodeContext.portContexts.get(portSide).size() - 1);
                spaceBetweenPorts += Math.max(0, additionalSpaceBetweenPorts);
                break;
        }
    }
    // Iterate over all ports and place them
    for (PortContext portContext : nodeContext.portContexts.get(portSide)) {
        portContext.portPosition.x = currentXPos + portContext.portMargin.left;
        portContext.portPosition.y = calculateHorizontalPortYCoordinate(portContext);
        // Update the x coordinate for the next port
        currentXPos += portContext.portMargin.left + portContext.port.getSize().x + portContext.portMargin.right + spaceBetweenPorts;
    }
}
Also used : PortAlignment(org.eclipse.elk.core.options.PortAlignment) AtomicCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle) ElkPadding(org.eclipse.elk.core.math.ElkPadding) PortContext(org.eclipse.elk.alg.common.nodespacing.internal.PortContext)

Example 3 with AtomicCell

use of org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell in project elk by eclipse.

the class VerticalPortPlacementSizeCalculator method calculateVerticalNodeSizeRequiredByFreePorts.

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Free
/**
 * Sets up inside port label spaces for free ports.
 */
private static void calculateVerticalNodeSizeRequiredByFreePorts(final NodeContext nodeContext, final PortSide portSide) {
    AtomicCell cell = nodeContext.insidePortLabelCells.get(portSide);
    // Handle the common case first: if there are no ports, set everything to zero
    if (nodeContext.portContexts.get(portSide).isEmpty()) {
        cell.getPadding().top = 0;
        cell.getPadding().bottom = 0;
        return;
    }
    // Set the padding to match the surrounding port space
    cell.getPadding().top = nodeContext.surroundingPortMargins.top;
    cell.getPadding().bottom = nodeContext.surroundingPortMargins.bottom;
    // required for their labels
    if (nodeContext.sizeConstraints.contains(SizeConstraint.PORT_LABELS)) {
        setupPortMargins(nodeContext, portSide);
    }
    double height = portHeightPlusPortPortSpacing(nodeContext, portSide);
    // For distributed port alignment, we need to surround the ports by a port-port spacing on each side
    if (nodeContext.getPortAlignment(portSide) == PortAlignment.DISTRIBUTED) {
        height += 2 * nodeContext.portPortSpacing;
    }
    // Set the cell size
    cell.getMinimumContentAreaSize().y = height;
}
Also used : AtomicCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell)

Example 4 with AtomicCell

use of org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell in project elk by eclipse.

the class VerticalPortPlacementSizeCalculator method calculateVerticalNodeSizeRequiredByFixedPosPorts.

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fixed Position
/**
 * Sets up inside port label spaces for fixed position ports. If the node size constraints include ports, we also
 * mess with the cell padding.
 */
private static void calculateVerticalNodeSizeRequiredByFixedPosPorts(final NodeContext nodeContext, final PortSide portSide) {
    double bottommostPortBorder = 0.0;
    // Check all ports on the correct side
    for (PortContext portContext : nodeContext.portContexts.get(portSide)) {
        bottommostPortBorder = Math.max(bottommostPortBorder, portContext.portPosition.y + portContext.port.getSize().y);
    }
    // Set the cell size and remove top padding since the cell size itself already includes all the space we need
    AtomicCell cell = nodeContext.insidePortLabelCells.get(portSide);
    cell.getPadding().top = 0;
    cell.getMinimumContentAreaSize().y = bottommostPortBorder;
}
Also used : AtomicCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell) PortContext(org.eclipse.elk.alg.common.nodespacing.internal.PortContext)

Example 5 with AtomicCell

use of org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell in project elk by eclipse.

the class VerticalPortPlacementSizeCalculator method calculateVerticalNodeSizeRequiredByFixedRatioPorts.

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fixed Ratio
/**
 * Sets up inside port label spaces for fixed ratio ports. If the node size constraints include ports, we also
 * mess with the cell padding.
 */
private static void calculateVerticalNodeSizeRequiredByFixedRatioPorts(final NodeContext nodeContext, final PortSide portSide) {
    AtomicCell cell = nodeContext.insidePortLabelCells.get(portSide);
    // Fetch the port contexts on the given side and abort if there are none
    Collection<PortContext> portContexts = nodeContext.portContexts.get(portSide);
    if (portContexts.isEmpty()) {
        cell.getPadding().top = 0;
        cell.getPadding().bottom = 0;
        return;
    }
    boolean portLabelsInside = nodeContext.portLabelsPlacement.contains(PortLabelPlacement.INSIDE);
    double minHeight = 0;
    // and the port labels are not placed next to the port)
    if (nodeContext.sizeConstraints.contains(SizeConstraint.PORT_LABELS)) {
        setupPortMargins(nodeContext, portSide);
    }
    // Go over all pairs of consecutive ports
    Iterator<PortContext> portContextIterator = portContexts.iterator();
    PortContext previousPortContext = null;
    double previousPortRatio = 0;
    double previousPortHeight = 0;
    while (portContextIterator.hasNext()) {
        // Get the next port and find out things about it
        PortContext currentPortContext = portContextIterator.next();
        double currentPortRatio = currentPortContext.port.getProperty(PortPlacementCalculator.PORT_RATIO_OR_POSITION);
        double currentPortHeight = currentPortContext.port.getSize().y;
        if (previousPortContext == null) {
            // port margins, if any
            if (nodeContext.surroundingPortMargins != null && nodeContext.surroundingPortMargins.top > 0) {
                minHeight = Math.max(minHeight, HorizontalPortPlacementSizeCalculator.minSizeRequiredToRespectSpacing(nodeContext.surroundingPortMargins.top + currentPortContext.portMargin.top, 0, currentPortRatio));
            }
        } else {
            double requiredSpace = previousPortHeight + previousPortContext.portMargin.bottom + nodeContext.portPortSpacing + currentPortContext.portMargin.top;
            minHeight = Math.max(minHeight, HorizontalPortPlacementSizeCalculator.minSizeRequiredToRespectSpacing(requiredSpace, previousPortRatio, currentPortRatio));
        }
        // Our current port is going to be the previous port during the next iteration
        previousPortContext = currentPortContext;
        previousPortRatio = currentPortRatio;
        previousPortHeight = currentPortHeight;
    }
    // if there are bottom surrounding port margins, apply those as well
    if (nodeContext.surroundingPortMargins != null && nodeContext.surroundingPortMargins.bottom > 0) {
        // We're using the port's bare width here because we don't care about label sizes on the bottommost port
        double requiredSpace = previousPortHeight + nodeContext.surroundingPortMargins.bottom;
        // We're only interested in the port's bottom margin if it's label is placed inside
        if (portLabelsInside) {
            requiredSpace += previousPortContext.portMargin.bottom;
        }
        minHeight = Math.max(minHeight, HorizontalPortPlacementSizeCalculator.minSizeRequiredToRespectSpacing(requiredSpace, previousPortRatio, 1));
    }
    // Set the cell size and remove top padding since the cell size itself already includes all the space we need
    cell.getPadding().top = 0;
    cell.getMinimumContentAreaSize().y = minHeight;
}
Also used : AtomicCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell) PortContext(org.eclipse.elk.alg.common.nodespacing.internal.PortContext)

Aggregations

AtomicCell (org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell)12 PortContext (org.eclipse.elk.alg.common.nodespacing.internal.PortContext)8 ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)3 ElkPadding (org.eclipse.elk.core.math.ElkPadding)2 KVector (org.eclipse.elk.core.math.KVector)2 PortAlignment (org.eclipse.elk.core.options.PortAlignment)2 LabelCell (org.eclipse.elk.alg.common.nodespacing.cellsystem.LabelCell)1 VerticalLabelAlignment (org.eclipse.elk.alg.common.nodespacing.cellsystem.VerticalLabelAlignment)1 RectangleStripOverlapRemover (org.eclipse.elk.alg.common.overlaps.RectangleStripOverlapRemover)1 OverlapRemovalDirection (org.eclipse.elk.alg.common.overlaps.RectangleStripOverlapRemover.OverlapRemovalDirection)1