Search in sources :

Example 1 with Direction

use of org.eclipse.elk.core.options.Direction in project elk by eclipse.

the class NodeLabelAndSizeCalculator method process.

/**
 * Processes the given node which is assumed to be a child of the given graph. Note that this method does not check
 * whether or not this is the case. The worst that can happen, however, is that wrong spacing values are applied
 * during processing.
 *
 * @param graph
 *            the node's parent graph.
 * @param node
 *            the node to process.
 * @param applyStuff
 *            {@code true} if the node should actually be resized and have its ports and labels positioned,
 *            {@code false} if we should only return the size that would be applied.
 * @param ignoreInsidePortLabels
 *            if {@code true}, we don't place port labels that should be placed inside. This is usually used in
 *            conjunction with {@code applyStuff} by layout algorithms that want to get a lower bound on a
 *            hierarchical node's size, but that handle inside port labels themselves.
 * @return the node's size that was or would be applied.
 */
public static KVector process(final GraphAdapter<?> graph, final NodeAdapter<?> node, final boolean applyStuff, final boolean ignoreInsidePortLabels) {
    // Note that, upon Miro's request, each phase of the algorithm was given a code name in the first version of
    // this code. We happily carry on fulfilling this request in this, the second version.
    /* PREPARATORY PREPARATIONS
         * 
         * Create the context objects that hold all of the information relevant to our calculations, including pointers
         * to all the components of the cell system. The different method calls will often just update information in
         * the context object (or nested objects) that subsequent method calls will make use of. Creating the port
         * contexts will also create label cells for each port that has labels.
         */
    NodeContext nodeContext = new NodeContext(graph, node);
    PortContextCreator.createPortContexts(nodeContext, ignoreInsidePortLabels);
    /* PHASE 1: WONDEROUS WATERFOWL
         *          Setup All Cells
         * 
         * Create all the label cells that will hold node labels, as well as the cell containers that will hold them,
         * for both inside and outside node labels. Also, assign node labels to the relevant label cells. If port
         * labels are to be placed on the inside, setup the inside port label cells with the appropriate paddings, and
         * set the width of the eastern and western ones to the maximum width of the labels they will contain. We can't
         * do that for the northern and southern cells yet because port label placement is more complicated there.
         */
    boolean horizontalLayoutMode = true;
    // use horizontal layout mode (which yields vertically stacked labels).
    if (graph != null && graph.hasProperty(CoreOptions.DIRECTION)) {
        final Direction layoutDirection = graph.getProperty(CoreOptions.DIRECTION);
        horizontalLayoutMode = layoutDirection == Direction.UNDEFINED || layoutDirection.isHorizontal();
    }
    NodeLabelCellCreator.createNodeLabelCells(nodeContext, false, horizontalLayoutMode);
    InsidePortLabelCellCreator.createInsidePortLabelCells(nodeContext);
    /* PHASE 2: DEFECTIVE DUCK
         *          Setup Client Area Space and Node Cell Padding
         * 
         * Apply the minimum client area size to the central grid container cell. Also, reserve space for ports that
         * extend inside the node due to negative port border offsets by setting up appropriate paddings on the main
         * node container cell.
         */
    NodeLabelAndSizeUtilities.setupMinimumClientAreaSize(nodeContext);
    NodeLabelAndSizeUtilities.setupNodePaddingForPortsWithOffset(nodeContext);
    /* PHASE 3: SALVAGEABLE SWAN
         *          Minimum Space Required to Place Ports
         * 
         * It is now time to find out how large the node needs to be if all ports are to be placed in a way that
         * satisfies all spacing constraints. This may or may not include the labels of ports. We remember these
         * information by setting the minimum width of north / south inside port label cells and the minimum height of
         * east / west inside port label cells. Since the east / west cells are surrounded by the north / south cells,
         * their height may be updated later once we know how high the north / south cells will be.
         */
    HorizontalPortPlacementSizeCalculator.calculateHorizontalPortPlacementSize(nodeContext);
    VerticalPortPlacementSizeCalculator.calculateVerticalPortPlacementSize(nodeContext);
    /* PHASE 4: DAMNABLE DUCKLING
         *          Setup Cell System Size Contribution Flags
         * 
         * Depending on the size constraints, the different cells may contribute to the height or to the width of the
         * node. In this phase, we setup the size contribution flags according to the size constraints. This lays the
         * groundwork for letting the cell system calculate stuff.
         */
    CellSystemConfigurator.configureCellSystemSizeContributions(nodeContext);
    /* PHASE 5: DUCK AND COVER
         *          Set Node Width and Place Horizontal Ports
         * 
         * We can now set the node's width and place the ports (and port labels) along the horizontal sides. Since we
         * have no idea how high the node is going to be yet, we place southern ports with the assumption that the
         * node has a height of 0. We will later have to offset those ports by the node's height. Setting the node
         * width has the side effect of computing a horizontal layout for the cell system.
         */
    NodeSizeCalculator.setNodeWidth(nodeContext);
    PortPlacementCalculator.placeHorizontalPorts(nodeContext);
    PortLabelPlacementCalculator.placeHorizontalPortLabels(nodeContext);
    /* PHASE 6: GIGANTIC GOOSE
         *          Set Node Height and Place Vertical Ports
         * 
         * We can now calculate the node's height and place the ports (and port labels) along the vertical sides. Also,
         * since we now know the node's height, we can finally correct the southern port positions. Before we can do
         * all that, however, we might need to update the height and padding of the eastern and western inside port
         * label cells to be sure that free ports are positioned properly.
         * 
         * Note that if we are to not apply stuff, we're done once we know the node's height. Which is why we stop at
         * that point.
         */
    CellSystemConfigurator.updateVerticalInsidePortLabelCellPadding(nodeContext);
    NodeSizeCalculator.setNodeHeight(nodeContext);
    if (!applyStuff) {
        return nodeContext.nodeSize;
    }
    NodeLabelAndSizeUtilities.offsetSouthernPortsByNodeSize(nodeContext);
    PortPlacementCalculator.placeVerticalPorts(nodeContext);
    PortLabelPlacementCalculator.placeVerticalPortLabels(nodeContext);
    /* PHASE 7: THANKSGIVING
         *          Place Labels and Apply Stuff
         * 
         * Since we now have the node's final size, we can now calculate the positions of the containers for outer node
         * labels and place all inner and outer node labels. Also, the port label cells have positions assigned to them
         * and can be told to apply positions to their labels. Finally, we can apply the node's size and all of the
         * port positions we have calculated.
         */
    LabelPlacer.placeLabels(nodeContext);
    NodeLabelAndSizeUtilities.setNodePadding(nodeContext);
    NodeLabelAndSizeUtilities.applyStuff(nodeContext);
    // Return the size
    return nodeContext.nodeSize;
}
Also used : NodeContext(org.eclipse.elk.alg.common.nodespacing.internal.NodeContext) Direction(org.eclipse.elk.core.options.Direction)

Example 2 with Direction

use of org.eclipse.elk.core.options.Direction in project elk by eclipse.

the class CompactionTest method testVeticalSpacings.

/**
 * Vertical spacing should be preserved when compaction upwards or downwards.
 */
@Test
public void testVeticalSpacings() {
    CGraph graph = new CGraph(EnumSet.allOf(Direction.class));
    // test horizontal direction
    CTestNodeSpacing one = new CTestNodeSpacing(new ElkRectangle(0, 0, 20, 20), 0d, 5d);
    graph.cNodes.add(one);
    CTestNodeSpacing two = new CTestNodeSpacing(new ElkRectangle(0, 50, 20, 20), 0d, 7d);
    graph.cNodes.add(two);
    CTestNodeSpacing three = new CTestNodeSpacing(new ElkRectangle(0, 150, 20, 20), 0d, 10d);
    graph.cNodes.add(three);
    compacter(graph).changeDirection(Direction.UP).compact().finish();
    assertEquals(0, one.hitbox.y, EPSILON);
    assertEquals(27, two.hitbox.y, EPSILON);
    assertEquals(57, three.hitbox.y, EPSILON);
    compacter(graph).changeDirection(Direction.DOWN).compact().finish();
    assertEquals(0, one.hitbox.y, EPSILON);
    assertEquals(27, two.hitbox.y, EPSILON);
    assertEquals(57, three.hitbox.y, EPSILON);
    compacter(graph).changeDirection(Direction.UP).compact().finish();
    assertEquals(0, one.hitbox.y, EPSILON);
    assertEquals(27, two.hitbox.y, EPSILON);
    assertEquals(57, three.hitbox.y, EPSILON);
}
Also used : CGraph(org.eclipse.elk.alg.layered.compaction.oned.CGraph) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle) Direction(org.eclipse.elk.core.options.Direction) Test(org.junit.Test)

Example 3 with Direction

use of org.eclipse.elk.core.options.Direction in project elk by eclipse.

the class CompactionTest method testSubsequentDirectionsCompaction.

/* --------------------------------------------------
     * Testing subsequent calls with different directions
     * -------------------------------------------------- */
@Test
public void testSubsequentDirectionsCompaction() {
    CGraph graph = new CGraph(EnumSet.allOf(Direction.class));
    CTestNode one = new CTestNode(new ElkRectangle(0, 0, 20, 20));
    graph.cNodes.add(one);
    CTestNode two = new CTestNode(new ElkRectangle(25, 0, 20, 20));
    graph.cNodes.add(two);
    CTestNode three = new CTestNode(new ElkRectangle(0, 25, 20, 20));
    graph.cNodes.add(three);
    CTestNode four = new CTestNode(new ElkRectangle(25, 25, 20, 20));
    graph.cNodes.add(four);
    Set<Direction> directions = EnumSet.of(Direction.LEFT, Direction.RIGHT, Direction.UP, Direction.DOWN);
    // subsequently apply all combinations of four subsequent compaction steps
    for (Direction d1 : directions) {
        for (Direction d2 : directions) {
            for (Direction d3 : directions) {
                for (Direction d4 : directions) {
                    compacter(graph).changeDirection(d1).compact().changeDirection(d2).compact().changeDirection(d3).compact().changeDirection(d4).compact().finish();
                    // the way we modeled the graph, every node should stay where it is
                    String currentDirections = d1 + " " + d2 + " " + d3 + " " + d4;
                    assertEquals(currentDirections, 0, one.hitbox.x, EPSILON);
                    assertEquals(currentDirections, 0, one.hitbox.y, EPSILON);
                    assertEquals(currentDirections, 25, two.hitbox.x, EPSILON);
                    assertEquals(currentDirections, 0, two.hitbox.y, EPSILON);
                    assertEquals(currentDirections, 0, three.hitbox.x, EPSILON);
                    assertEquals(currentDirections, 25, three.hitbox.y, EPSILON);
                    assertEquals(currentDirections, 25, four.hitbox.x, EPSILON);
                    assertEquals(currentDirections, 25, four.hitbox.y, EPSILON);
                }
            }
        }
    }
}
Also used : CGraph(org.eclipse.elk.alg.layered.compaction.oned.CGraph) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle) Direction(org.eclipse.elk.core.options.Direction) Test(org.junit.Test)

Example 4 with Direction

use of org.eclipse.elk.core.options.Direction in project elk by eclipse.

the class CompactionTest method testHorizontalSpacings.

/* --------------------------------------------------
     *        Testing different kinds of spacings.
     * --------------------------------------------------*/
/*
     * We support different spacing values between nodes and edges in vertical and horizontal
     * direction. Thereby "vertical" and "horizontal" depends on the compaction direction.
     * Furthermore, we support individual spacings between any pair of nodes.
     */
/**
 * Horizontal spacing should be preserved when compaction leftwards or rightwards.
 */
@Test
public void testHorizontalSpacings() {
    CGraph graph = new CGraph(EnumSet.allOf(Direction.class));
    // test horizontal direction
    CTestNodeSpacing one = new CTestNodeSpacing(new ElkRectangle(0, 0, 20, 20), 5d, 0d);
    graph.cNodes.add(one);
    CTestNodeSpacing two = new CTestNodeSpacing(new ElkRectangle(50, 0, 20, 20), 7d, 0d);
    graph.cNodes.add(two);
    CTestNodeSpacing three = new CTestNodeSpacing(new ElkRectangle(150, 0, 20, 20), 10d, 0d);
    graph.cNodes.add(three);
    compacter(graph).changeDirection(Direction.LEFT).compact().finish();
    assertEquals(0, one.hitbox.x, EPSILON);
    assertEquals(27, two.hitbox.x, EPSILON);
    assertEquals(57, three.hitbox.x, EPSILON);
    compacter(graph).changeDirection(Direction.RIGHT).compact().finish();
    assertEquals(0, one.hitbox.x, EPSILON);
    assertEquals(27, two.hitbox.x, EPSILON);
    assertEquals(57, three.hitbox.x, EPSILON);
    compacter(graph).changeDirection(Direction.LEFT).compact().finish();
    assertEquals(0, one.hitbox.x, EPSILON);
    assertEquals(27, two.hitbox.x, EPSILON);
    assertEquals(57, three.hitbox.x, EPSILON);
}
Also used : CGraph(org.eclipse.elk.alg.layered.compaction.oned.CGraph) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle) Direction(org.eclipse.elk.core.options.Direction) Test(org.junit.Test)

Example 5 with Direction

use of org.eclipse.elk.core.options.Direction in project elk by eclipse.

the class GraphConfigurator method configureGraphProperties.

/**
 * Set special layout options for the layered graph.
 *
 * @param lgraph a new layered graph
 */
private void configureGraphProperties(final LGraph lgraph) {
    // check the bounds of some layout options
    // TODO Find a new concept for checking validity of bounds
    // lgraph.checkProperties(InternalProperties.SPACING, InternalProperties.BORDER_SPACING,
    // Properties.THOROUGHNESS, InternalProperties.ASPECT_RATIO);
    double edgeSpacing = lgraph.getProperty(LayeredOptions.SPACING_EDGE_EDGE);
    if (edgeSpacing < MIN_EDGE_SPACING) {
        // Make sure the resulting edge spacing is at least 2 in order to avoid overlapping edges.
        lgraph.setProperty(LayeredOptions.SPACING_EDGE_EDGE, MIN_EDGE_SPACING);
    }
    Direction direction = lgraph.getProperty(LayeredOptions.DIRECTION);
    if (direction == Direction.UNDEFINED) {
        lgraph.setProperty(LayeredOptions.DIRECTION, LGraphUtil.getDirection(lgraph));
    }
    // set the random number generator based on the random seed option
    Integer randomSeed = lgraph.getProperty(LayeredOptions.RANDOM_SEED);
    if (randomSeed == 0) {
        lgraph.setProperty(InternalProperties.RANDOM, new Random());
    } else {
        lgraph.setProperty(InternalProperties.RANDOM, new Random(randomSeed));
    }
    Boolean favorStraightness = lgraph.getProperty(LayeredOptions.NODE_PLACEMENT_FAVOR_STRAIGHT_EDGES);
    if (favorStraightness == null) {
        lgraph.setProperty(LayeredOptions.NODE_PLACEMENT_FAVOR_STRAIGHT_EDGES, lgraph.getProperty(LayeredOptions.EDGE_ROUTING) == EdgeRouting.ORTHOGONAL);
    }
    // copy the port constraints to keep a list of original port constraints
    copyPortContraints(lgraph);
    // pre-calculate spacing information
    Spacings spacings = new Spacings(lgraph);
    lgraph.setProperty(InternalProperties.SPACINGS, spacings);
}
Also used : Random(java.util.Random) Spacings(org.eclipse.elk.alg.layered.options.Spacings) Direction(org.eclipse.elk.core.options.Direction)

Aggregations

Direction (org.eclipse.elk.core.options.Direction)30 LNode (org.eclipse.elk.alg.layered.graph.LNode)9 KVector (org.eclipse.elk.core.math.KVector)7 PortSide (org.eclipse.elk.core.options.PortSide)7 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)6 ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)5 PortConstraints (org.eclipse.elk.core.options.PortConstraints)5 ElkNode (org.eclipse.elk.graph.ElkNode)5 CGroup (org.eclipse.elk.alg.layered.compaction.oned.CGroup)4 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)4 GraphProperties (org.eclipse.elk.alg.layered.options.GraphProperties)4 SizeConstraint (org.eclipse.elk.core.options.SizeConstraint)4 ElkEdge (org.eclipse.elk.graph.ElkEdge)4 ElkPort (org.eclipse.elk.graph.ElkPort)4 Test (org.junit.Test)4 CGraph (org.eclipse.elk.alg.layered.compaction.oned.CGraph)3 CNode (org.eclipse.elk.alg.layered.compaction.oned.CNode)3 LPort (org.eclipse.elk.alg.layered.graph.LPort)3 ElkLabel (org.eclipse.elk.graph.ElkLabel)3 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)2