Search in sources :

Example 71 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class ElkGraphLayoutTransferrer method applyLayout.

/**
 * Applies the layout information contained in the given LGraph to the ElkGraph elements it was
 * created from. All source ElkGraph elements are expected to be accessible through their LGraph
 * counterparts through the {@link InternalProperties#ORIGIN} property.
 *
 * @param lgraph the LGraph whose layout information to apply.
 */
public void applyLayout(final LGraph lgraph) {
    Object graphOrigin = lgraph.getProperty(InternalProperties.ORIGIN);
    if (!(graphOrigin instanceof ElkNode)) {
        return;
    }
    // The ElkNode that represents this graph in the original ElkGraph
    ElkNode parentElkNode = (ElkNode) graphOrigin;
    // The LNode that represents this graph in the upper hierarchy level, if any
    LNode parentLNode = (LNode) lgraph.getParentNode();
    // Get the offset to be added to all coordinates
    KVector offset = new KVector(lgraph.getOffset());
    // Adjust offset (and with it the positions) by the requested padding
    LPadding lPadding = lgraph.getPadding();
    offset.x += lPadding.left;
    offset.y += lPadding.top;
    // Set node padding, if it was computed during layout
    final EnumSet<SizeOptions> sizeOptions = parentElkNode.getProperty(LayeredOptions.NODE_SIZE_OPTIONS);
    if (sizeOptions.contains(SizeOptions.COMPUTE_PADDING)) {
        ElkPadding padding = parentElkNode.getProperty(LayeredOptions.PADDING);
        padding.setBottom(lPadding.bottom);
        padding.setTop(lPadding.top);
        padding.setLeft(lPadding.left);
        padding.setRight(lPadding.right);
    }
    // Along the way, we collect the list of edges to be processed later
    List<LEdge> edgeList = Lists.newArrayList();
    // Process the nodes
    for (LNode lnode : lgraph.getLayerlessNodes()) {
        if (representsNode(lnode)) {
            applyNodeLayout(lnode, offset);
        } else if (representsExternalPort(lnode) && parentLNode == null) {
            // We have an external port here on the top-most hierarchy level of the current (possibly
            // hierarchical) layout run; set its position
            ElkPort elkport = (ElkPort) lnode.getProperty(InternalProperties.ORIGIN);
            KVector portPosition = LGraphUtil.getExternalPortPosition(lgraph, lnode, elkport.getWidth(), elkport.getHeight());
            elkport.setLocation(portPosition.x, portPosition.y);
        }
        // correctly)
        for (LPort port : lnode.getPorts()) {
            port.getOutgoingEdges().stream().filter(edge -> !LGraphUtil.isDescendant(edge.getTarget().getNode(), lnode)).forEach(edge -> edgeList.add(edge));
        }
    }
    // Collect edges that go from the current graph's representing LNode down into its descendants
    if (parentLNode != null) {
        for (LPort port : parentLNode.getPorts()) {
            port.getOutgoingEdges().stream().filter(edge -> LGraphUtil.isDescendant(edge.getTarget().getNode(), parentLNode)).forEach(edge -> edgeList.add(edge));
        }
    }
    // Iterate through all edges
    EdgeRouting routing = parentElkNode.getProperty(LayeredOptions.EDGE_ROUTING);
    for (LEdge ledge : edgeList) {
        applyEdgeLayout(ledge, routing, offset, lPadding);
    }
    // Setup the parent node
    applyParentNodeLayout(lgraph);
    // Process nested subgraphs
    for (LNode lnode : lgraph.getLayerlessNodes()) {
        LGraph nestedGraph = lnode.getNestedGraph();
        if (nestedGraph != null) {
            applyLayout(nestedGraph);
        }
    }
}
Also used : GraphProperties(org.eclipse.elk.alg.layered.options.GraphProperties) LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) ElkNode(org.eclipse.elk.graph.ElkNode) ElkPort(org.eclipse.elk.graph.ElkPort) PortLabelPlacement(org.eclipse.elk.core.options.PortLabelPlacement) LayeredOptions(org.eclipse.elk.alg.layered.options.LayeredOptions) KVectorChain(org.eclipse.elk.core.math.KVectorChain) ElkUtil(org.eclipse.elk.core.util.ElkUtil) Lists(com.google.common.collect.Lists) LabelDummySwitcher(org.eclipse.elk.alg.layered.intermediate.LabelDummySwitcher) InternalProperties(org.eclipse.elk.alg.layered.options.InternalProperties) ElkPadding(org.eclipse.elk.core.math.ElkPadding) EnumSet(java.util.EnumSet) NodePlacementStrategy(org.eclipse.elk.alg.layered.options.NodePlacementStrategy) NodeFlexibility(org.eclipse.elk.alg.layered.options.NodeFlexibility) PortConstraints(org.eclipse.elk.core.options.PortConstraints) ElkLabel(org.eclipse.elk.graph.ElkLabel) KVector(org.eclipse.elk.core.math.KVector) SizeOptions(org.eclipse.elk.core.options.SizeOptions) Set(java.util.Set) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) LGraphUtil(org.eclipse.elk.alg.layered.graph.LGraphUtil) LPadding(org.eclipse.elk.alg.layered.graph.LPadding) List(java.util.List) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) LPort(org.eclipse.elk.alg.layered.graph.LPort) EdgeRouting(org.eclipse.elk.core.options.EdgeRouting) LNode(org.eclipse.elk.alg.layered.graph.LNode) ElkEdge(org.eclipse.elk.graph.ElkEdge) ElkGraphUtil(org.eclipse.elk.graph.util.ElkGraphUtil) ElkNode(org.eclipse.elk.graph.ElkNode) SizeOptions(org.eclipse.elk.core.options.SizeOptions) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) ElkPort(org.eclipse.elk.graph.ElkPort) LPadding(org.eclipse.elk.alg.layered.graph.LPadding) EdgeRouting(org.eclipse.elk.core.options.EdgeRouting) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) ElkPadding(org.eclipse.elk.core.math.ElkPadding)

Example 72 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class ElkGraphLayoutTransferrer method calculateHierarchicalOffset.

/**
 * If the coordinates of an edge must be relative to a different node than they are in the algorithm, this
 * method returns the correct offset to translate from the algorithm's coordinate system to the necessary
 * target coordinate system.
 *
 * @return the offset vector, which may simply be zero (but not {@code null}). Must not be modified.
 */
private KVector calculateHierarchicalOffset(final LEdge ledge) {
    LGraph targetCoordinateSystem = ledge.getProperty(InternalProperties.COORDINATE_SYSTEM_ORIGIN);
    if (targetCoordinateSystem != null) {
        KVector result = new KVector();
        // Edges this method is called on are always in the coordinate system of their source
        LGraph currentGraph = ledge.getSource().getNode().getGraph();
        while (currentGraph != targetCoordinateSystem) {
            // The current graph should always have an upper level if we have not reached the target graph yet;
            LNode representingNode = currentGraph.getParentNode();
            currentGraph = representingNode.getGraph();
            result.add(representingNode.getPosition()).add(currentGraph.getOffset()).add(currentGraph.getPadding().left, currentGraph.getPadding().top);
        }
        return result;
    }
    // No coordinate system conversion is required
    return ZERO_OFFSET;
}
Also used : LNode(org.eclipse.elk.alg.layered.graph.LNode) LGraph(org.eclipse.elk.alg.layered.graph.LGraph) KVector(org.eclipse.elk.core.math.KVector)

Example 73 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class CommentPostprocessor method process.

/**
 * Process a node with its connected comment boxes.
 *
 * @param node a normal node
 * @param topBoxes a list of boxes to be placed on top, or {@code null}
 * @param bottomBoxes a list of boxes to be placed in the bottom, or {@code null}
 */
private void process(final LNode node, final List<LNode> topBoxes, final List<LNode> bottomBoxes) {
    KVector nodePos = node.getPosition();
    KVector nodeSize = node.getSize();
    LMargin margin = node.getMargin();
    double commentCommentSpacing = Spacings.getIndividualOrDefault(node, LayeredOptions.SPACING_COMMENT_COMMENT);
    if (topBoxes != null) {
        // determine the total width and maximal height of the top boxes
        double boxesWidth = commentCommentSpacing * (topBoxes.size() - 1);
        double maxHeight = 0;
        for (LNode box : topBoxes) {
            boxesWidth += box.getSize().x;
            maxHeight = Math.max(maxHeight, box.getSize().y);
        }
        // place the boxes on top of the node, horizontally centered around the node itself
        double x = nodePos.x - (boxesWidth - nodeSize.x) / 2;
        double baseLine = nodePos.y - margin.top + maxHeight;
        double anchorInc = nodeSize.x / (topBoxes.size() + 1);
        double anchorX = anchorInc;
        for (LNode box : topBoxes) {
            box.getPosition().x = x;
            box.getPosition().y = baseLine - box.getSize().y;
            x += box.getSize().x + commentCommentSpacing;
            // set source and target point for the connecting edge
            LPort boxPort = getBoxPort(box);
            boxPort.getPosition().x = box.getSize().x / 2 - boxPort.getAnchor().x;
            boxPort.getPosition().y = box.getSize().y;
            LPort nodePort = box.getProperty(InternalProperties.COMMENT_CONN_PORT);
            if (nodePort.getDegree() == 1) {
                nodePort.getPosition().x = anchorX - nodePort.getAnchor().x;
                nodePort.getPosition().y = 0;
                nodePort.setNode(node);
            }
            anchorX += anchorInc;
        }
    }
    if (bottomBoxes != null) {
        // determine the total width and maximal height of the bottom boxes
        double boxesWidth = commentCommentSpacing * (bottomBoxes.size() - 1);
        double maxHeight = 0;
        for (LNode box : bottomBoxes) {
            boxesWidth += box.getSize().x;
            maxHeight = Math.max(maxHeight, box.getSize().y);
        }
        // place the boxes in the bottom of the node, horizontally centered around the node itself
        double x = nodePos.x - (boxesWidth - nodeSize.x) / 2;
        double baseLine = nodePos.y + nodeSize.y + margin.bottom - maxHeight;
        double anchorInc = nodeSize.x / (bottomBoxes.size() + 1);
        double anchorX = anchorInc;
        for (LNode box : bottomBoxes) {
            box.getPosition().x = x;
            box.getPosition().y = baseLine;
            x += box.getSize().x + commentCommentSpacing;
            // set source and target point for the connecting edge
            LPort boxPort = getBoxPort(box);
            boxPort.getPosition().x = box.getSize().x / 2 - boxPort.getAnchor().x;
            boxPort.getPosition().y = 0;
            LPort nodePort = box.getProperty(InternalProperties.COMMENT_CONN_PORT);
            if (nodePort.getDegree() == 1) {
                nodePort.getPosition().x = anchorX - nodePort.getAnchor().x;
                nodePort.getPosition().y = nodeSize.y;
                nodePort.setNode(node);
            }
            anchorX += anchorInc;
        }
    }
}
Also used : LMargin(org.eclipse.elk.alg.layered.graph.LMargin) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector)

Example 74 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class CompoundGraphPreprocessor method createExternalPortDummy.

/**
 * Retrieves a dummy node to be used to represent a new external port of the parent node and to
 * connect a new segment of the given hierarchical edge to. A proper dummy node might already
 * have been created; if so, that one is returned.
 *
 * @param graph
 *            the graph.
 * @param parentNode
 *            the graph's parent node.
 * @param portType
 *            the type of the new external port.
 * @param edge
 *            the edge that will be connected to the external port.
 * @return an appropriate external port dummy.
 */
private LNode createExternalPortDummy(final LGraph graph, final LNode parentNode, final PortType portType, final PortSide portSide, final LEdge edge) {
    LNode dummyNode = null;
    // find the port on the outside of its parent node that the edge connects to
    LPort outsidePort = portType == PortType.INPUT ? edge.getSource() : edge.getTarget();
    Direction layoutDirection = LGraphUtil.getDirection(graph);
    // check if the edge connects to the parent node or to something way outside...
    if (outsidePort.getNode() == parentNode) {
        // we need to check if a dummy node has already been created for the port
        dummyNode = dummyNodeMap.get(outsidePort);
        if (dummyNode == null) {
            // Ticket #160 explains why we need to pass on a position here. While that works fine to determine port
            // orders, the exact port positions might yet need to be adjusted for some inside paddings
            dummyNode = LGraphUtil.createExternalPortDummy(outsidePort, parentNode.getProperty(LayeredOptions.PORT_CONSTRAINTS), portSide, calculateNetFlow(outsidePort), null, outsidePort.getPosition(), outsidePort.getSize(), layoutDirection, graph);
            dummyNode.setProperty(InternalProperties.ORIGIN, outsidePort);
            dummyNodeMap.put(outsidePort, dummyNode);
        }
    } else {
        // We create a new dummy node in any case, and since there is no port yet we have to create one as well. We
        // do need to pass a position vector to keep an NPE from being thrown (#160), but it is questionable
        // whether this part of the code should actually be used with anything other than fixed port constraints.
        double thickness = edge.getProperty(LayeredOptions.EDGE_THICKNESS);
        dummyNode = LGraphUtil.createExternalPortDummy(createExternalPortProperties(graph), parentNode.getProperty(LayeredOptions.PORT_CONSTRAINTS), portSide, calculateNetFlow(outsidePort), null, new KVector(), new KVector(thickness, thickness), layoutDirection, graph);
        LPort dummyPort = createPortForDummy(dummyNode, parentNode, portType);
        dummyNode.setProperty(InternalProperties.ORIGIN, dummyPort);
        dummyNodeMap.put(dummyPort, dummyNode);
    }
    // set a few graph properties
    graph.getProperty(InternalProperties.GRAPH_PROPERTIES).add(GraphProperties.EXTERNAL_PORTS);
    if (graph.getProperty(LayeredOptions.PORT_CONSTRAINTS).isSideFixed()) {
        graph.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
    } else {
        graph.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FREE);
    }
    return dummyNode;
}
Also used : LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) Direction(org.eclipse.elk.core.options.Direction)

Example 75 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class EndLabelPreprocessor method updateNodeMargins.

// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Node Margins
/**
 * Updates the node's margins to account for its end labels.
 */
private void updateNodeMargins(final LNode node, final LabelCell[] labelCells) {
    LMargin nodeMargin = node.getMargin();
    KVector nodeSize = node.getSize();
    // Calculate the rectangle that describes the node's current margin
    ElkRectangle nodeMarginRectangle = new ElkRectangle(-nodeMargin.left, -nodeMargin.top, nodeMargin.left + nodeSize.x + nodeMargin.right, nodeMargin.top + nodeSize.y + nodeMargin.bottom);
    // Union the rectangle with each rectangle that describes a label cell
    for (LabelCell labelCell : labelCells) {
        if (labelCell != null) {
            nodeMarginRectangle.union(labelCell.getCellRectangle());
        }
    }
    // Reapply the new rectangle to the margin
    nodeMargin.left = -nodeMarginRectangle.x;
    nodeMargin.top = -nodeMarginRectangle.y;
    nodeMargin.right = nodeMarginRectangle.width - nodeMargin.left - nodeSize.x;
    nodeMargin.bottom = nodeMarginRectangle.height - nodeMargin.top - nodeSize.y;
}
Also used : LMargin(org.eclipse.elk.alg.layered.graph.LMargin) LabelCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.LabelCell) KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle)

Aggregations

KVector (org.eclipse.elk.core.math.KVector)292 KVectorChain (org.eclipse.elk.core.math.KVectorChain)52 ElkNode (org.eclipse.elk.graph.ElkNode)49 LNode (org.eclipse.elk.alg.layered.graph.LNode)39 LPort (org.eclipse.elk.alg.layered.graph.LPort)37 ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)36 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)35 Test (org.junit.Test)30 ElkEdge (org.eclipse.elk.graph.ElkEdge)28 ElkLabel (org.eclipse.elk.graph.ElkLabel)27 ElkEdgeSection (org.eclipse.elk.graph.ElkEdgeSection)26 ElkPadding (org.eclipse.elk.core.math.ElkPadding)25 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)20 PortSide (org.eclipse.elk.core.options.PortSide)19 ElkPort (org.eclipse.elk.graph.ElkPort)18 SizeConstraint (org.eclipse.elk.core.options.SizeConstraint)17 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)15 ArrayList (java.util.ArrayList)13 Layer (org.eclipse.elk.alg.layered.graph.Layer)12 LMargin (org.eclipse.elk.alg.layered.graph.LMargin)11