Search in sources :

Example 1 with KVector

use of org.eclipse.elk.core.math.KVector in project lingua-franca by lf-lang.

the class LinguaFrancaSynthesis method transformReactorNetwork.

private Collection<KNode> transformReactorNetwork(ReactorInstance reactorInstance, Map<PortInstance, KPort> parentInputPorts, Map<PortInstance, KPort> parentOutputPorts, Map<ReactorInstance, KNode> allReactorNodes) {
    List<KNode> nodes = new ArrayList<>();
    Table<ReactorInstance, PortInstance, KPort> inputPorts = HashBasedTable.create();
    Table<ReactorInstance, PortInstance, KPort> outputPorts = HashBasedTable.create();
    Map<ReactionInstance, KNode> reactionNodes = new HashMap<>();
    Map<KPort, KNode> directConnectionDummyNodes = new HashMap<>();
    Multimap<ActionInstance, KPort> actionDestinations = HashMultimap.create();
    Multimap<ActionInstance, KPort> actionSources = HashMultimap.create();
    Map<TimerInstance, KNode> timerNodes = new HashMap<>();
    KNode startupNode = _kNodeExtensions.createNode();
    boolean startupUsed = false;
    KNode shutdownNode = _kNodeExtensions.createNode();
    boolean shutdownUsed = false;
    // Transform instances
    int index = 0;
    for (ReactorInstance child : ListExtensions.reverseView(reactorInstance.children)) {
        Boolean expansionState = MemorizingExpandCollapseAction.getExpansionState(child);
        Collection<KNode> rNodes = createReactorNode(child, expansionState != null ? expansionState : false, inputPorts, outputPorts, allReactorNodes);
        setLayoutOption(IterableExtensions.<KNode>head(rNodes), CoreOptions.PRIORITY, index);
        nodes.addAll(rNodes);
        index++;
    }
    // Create timers
    for (TimerInstance timer : reactorInstance.timers) {
        KNode node = associateWith(_kNodeExtensions.createNode(), timer.getDefinition());
        NamedInstanceUtil.linkInstance(node, timer);
        _utilityExtensions.setID(node, timer.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(timer.getDefinition(), node));
        timerNodes.put(timer, node);
        _linguaFrancaShapeExtensions.addTimerFigure(node, timer);
    }
    // Create reactions
    for (ReactionInstance reaction : ListExtensions.reverseView(reactorInstance.reactions)) {
        int idx = reactorInstance.reactions.indexOf(reaction);
        KNode node = associateWith(_kNodeExtensions.createNode(), reaction.getDefinition());
        NamedInstanceUtil.linkInstance(node, reaction);
        _utilityExtensions.setID(node, reaction.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(reaction.getDefinition(), node));
        reactionNodes.put(reaction, node);
        setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
        // always place with higher priority than reactor nodes
        setLayoutOption(node, CoreOptions.PRIORITY, (reactorInstance.reactions.size() - idx) * 10);
        // try order reactions vertically if in one layer
        setLayoutOption(node, LayeredOptions.POSITION, new KVector(0, idx));
        _linguaFrancaShapeExtensions.addReactionFigure(node, reaction);
        // connect input
        KPort port = null;
        for (TriggerInstance<?> trigger : reaction.triggers) {
            port = addInvisiblePort(node);
            setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.WEST);
            int triggersSize = reaction.triggers != null ? reaction.triggers.size() : 0;
            int sourcesSize = reaction.sources != null ? reaction.sources.size() : 0;
            if (getBooleanValue(REACTIONS_USE_HYPEREDGES) || triggersSize + sourcesSize == 1) {
                // manual adjustment disabling automatic one
                setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, (double) -LinguaFrancaShapeExtensions.REACTION_POINTINESS);
            }
            if (trigger.isStartup()) {
                connect(createDependencyEdge(((TriggerInstance.BuiltinTriggerVariable) trigger.getDefinition()).definition), startupNode, port);
                startupUsed = true;
            } else if (trigger.isShutdown()) {
                connect(createDelayEdge(((TriggerInstance.BuiltinTriggerVariable) trigger.getDefinition()).definition), shutdownNode, port);
                shutdownUsed = true;
            } else if (trigger instanceof ActionInstance) {
                actionDestinations.put(((ActionInstance) trigger), port);
            } else if (trigger instanceof PortInstance) {
                KPort src = null;
                PortInstance triggerAsPort = (PortInstance) trigger;
                if (triggerAsPort.getParent() == reactorInstance) {
                    src = parentInputPorts.get(trigger);
                } else {
                    src = outputPorts.get(triggerAsPort.getParent(), trigger);
                }
                if (src != null) {
                    connect(createDependencyEdge(triggerAsPort.getDefinition()), src, port);
                }
            } else if (trigger instanceof TimerInstance) {
                KNode src = timerNodes.get(trigger);
                if (src != null) {
                    connect(createDependencyEdge(trigger.getDefinition()), src, port);
                }
            }
        }
        // port = null // create new ports
        for (TriggerInstance<?> dep : reaction.sources) {
            if (reaction.triggers.contains(dep))
                continue;
            if (!(getBooleanValue(REACTIONS_USE_HYPEREDGES) && port != null)) {
                port = addInvisiblePort(node);
                setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.WEST);
                int triggersSize = reaction.triggers != null ? reaction.triggers.size() : 0;
                int sourcesSize = reaction.sources != null ? reaction.sources.size() : 0;
                if (getBooleanValue(REACTIONS_USE_HYPEREDGES) || triggersSize + sourcesSize == 1) {
                    // manual adjustment disabling automatic one
                    setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, (double) -LinguaFrancaShapeExtensions.REACTION_POINTINESS);
                }
            }
            if (dep instanceof PortInstance) {
                KPort src = null;
                PortInstance depAsPort = (PortInstance) dep;
                if (dep.getParent() == reactorInstance) {
                    src = parentInputPorts.get(dep);
                } else {
                    src = outputPorts.get(depAsPort.getParent(), dep);
                }
                if (src != null) {
                    connect(createDependencyEdge(dep.getDefinition()), src, port);
                }
            }
        }
        // connect outputs
        // create new ports
        port = null;
        Set<TriggerInstance<?>> iterSet = reaction.effects != null ? reaction.effects : new HashSet<>();
        for (TriggerInstance<?> effect : iterSet) {
            port = addInvisiblePort(node);
            setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.EAST);
            if (effect instanceof ActionInstance) {
                actionSources.put((ActionInstance) effect, port);
            } else if (effect instanceof PortInstance) {
                KPort dst = null;
                PortInstance effectAsPort = (PortInstance) effect;
                if (effectAsPort.isOutput()) {
                    dst = parentOutputPorts.get(effect);
                } else {
                    dst = inputPorts.get(effectAsPort.getParent(), effect);
                }
                if (dst != null) {
                    connect(createDependencyEdge(effect), port, dst);
                }
            }
        }
    }
    // Connect actions
    Set<ActionInstance> actions = new HashSet<>();
    actions.addAll(actionSources.keySet());
    actions.addAll(actionDestinations.keySet());
    for (ActionInstance action : actions) {
        KNode node = associateWith(_kNodeExtensions.createNode(), action.getDefinition());
        NamedInstanceUtil.linkInstance(node, action);
        _utilityExtensions.setID(node, action.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(action.getDefinition(), node));
        setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
        Pair<KPort, KPort> ports = _linguaFrancaShapeExtensions.addActionFigureAndPorts(node, action.isPhysical() ? "P" : "L");
        // TODO handle variables?
        if (action.getMinDelay() != null && action.getMinDelay() != ActionInstance.DEFAULT_MIN_DELAY) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("min delay: %s", action.getMinDelay().toString()), 7);
        }
        // TODO default value?
        if (action.getDefinition().getMinSpacing() != null) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("min spacing: %s", action.getMinSpacing().toString()), 7);
        }
        if (!StringExtensions.isNullOrEmpty(action.getDefinition().getPolicy())) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("policy: %s", action.getPolicy().toString()), 7);
        }
        // connect source
        for (KPort source : actionSources.get(action)) {
            connect(createDelayEdge(action), source, ports.getKey());
        }
        // connect targets
        for (KPort target : actionDestinations.get(action)) {
            connect(createDelayEdge(action), ports.getValue(), target);
        }
    }
    // Transform connections.
    // First, collect all the source ports.
    List<PortInstance> sourcePorts = new LinkedList<>(reactorInstance.inputs);
    for (ReactorInstance child : reactorInstance.children) {
        sourcePorts.addAll(child.outputs);
    }
    for (PortInstance leftPort : sourcePorts) {
        KPort source = leftPort.getParent() == reactorInstance ? parentInputPorts.get(leftPort) : outputPorts.get(leftPort.getParent(), leftPort);
        for (SendRange sendRange : leftPort.getDependentPorts()) {
            for (RuntimeRange<PortInstance> rightRange : sendRange.destinations) {
                PortInstance rightPort = rightRange.instance;
                KPort target = rightPort.getParent() == reactorInstance ? parentOutputPorts.get(rightPort) : inputPorts.get(rightPort.getParent(), rightPort);
                // There should be a connection, but skip if not.
                Connection connection = sendRange.connection;
                if (connection != null) {
                    KEdge edge = createIODependencyEdge(connection, (leftPort.isMultiport() || rightPort.isMultiport()));
                    if (connection.getDelay() != null) {
                        KLabel delayLabel = _kLabelExtensions.addCenterEdgeLabel(edge, ASTUtils.toText(connection.getDelay()));
                        associateWith(delayLabel, connection.getDelay());
                        if (connection.isPhysical()) {
                            _linguaFrancaStyleExtensions.applyOnEdgePysicalDelayStyle(delayLabel, reactorInstance.isMainOrFederated() ? Colors.WHITE : Colors.GRAY_95);
                        } else {
                            _linguaFrancaStyleExtensions.applyOnEdgeDelayStyle(delayLabel);
                        }
                    } else if (connection.isPhysical()) {
                        KLabel physicalConnectionLabel = _kLabelExtensions.addCenterEdgeLabel(edge, "---");
                        _linguaFrancaStyleExtensions.applyOnEdgePysicalStyle(physicalConnectionLabel, reactorInstance.isMainOrFederated() ? Colors.WHITE : Colors.GRAY_95);
                    }
                    if (source != null && target != null) {
                        // check for inside loop (direct in -> out connection with delay)
                        if (parentInputPorts.values().contains(source) && parentOutputPorts.values().contains(target)) {
                            // edge.setLayoutOption(CoreOptions.INSIDE_SELF_LOOPS_YO, true) // Does not work as expected
                            // Introduce dummy node to enable direct connection (that is also hidden when collapsed)
                            KNode dummy = _kNodeExtensions.createNode();
                            if (directConnectionDummyNodes.containsKey(target)) {
                                dummy = directConnectionDummyNodes.get(target);
                            } else {
                                nodes.add(dummy);
                                directConnectionDummyNodes.put(target, dummy);
                                _kRenderingExtensions.addInvisibleContainerRendering(dummy);
                                _kNodeExtensions.setNodeSize(dummy, 0, 0);
                                KEdge extraEdge = createIODependencyEdge(null, (leftPort.isMultiport() || rightPort.isMultiport()));
                                connect(extraEdge, dummy, target);
                            }
                            connect(edge, source, dummy);
                        } else {
                            connect(edge, source, target);
                        }
                    }
                }
            }
        }
    }
    // Add startup/shutdown
    if (startupUsed) {
        _linguaFrancaShapeExtensions.addStartupFigure(startupNode);
        nodes.add(0, startupNode);
        setLayoutOption(startupNode, LayeredOptions.LAYERING_LAYER_CONSTRAINT, LayerConstraint.FIRST);
        if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
            KPort port = addInvisiblePort(startupNode);
            startupNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    if (shutdownUsed) {
        _linguaFrancaShapeExtensions.addShutdownFigure(shutdownNode);
        nodes.add(0, shutdownNode);
        if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
            // connect all edges to one port
            KPort port = addInvisiblePort(shutdownNode);
            shutdownNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    // Postprocess timer nodes
    if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
        // connect all edges to one port
        for (KNode timerNode : timerNodes.values()) {
            KPort port = addInvisiblePort(timerNode);
            timerNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    // Add reaction order edges (add last to have them on top of other edges)
    if (reactorInstance.reactions.size() > 1) {
        KNode prevNode = reactionNodes.get(IterableExtensions.head(reactorInstance.reactions));
        Iterable<KNode> iterList = IterableExtensions.map(IterableExtensions.drop(reactorInstance.reactions, 1), reactionNodes::get);
        for (KNode node : iterList) {
            KEdge edge = createOrderEdge();
            edge.setSource(prevNode);
            edge.setTarget(node);
            edge.setProperty(CoreOptions.NO_LAYOUT, true);
            // Do not remove them, as they are needed for cycle detection
            KRendering edgeRendering = _kRenderingExtensions.getKRendering(edge);
            _kRenderingExtensions.setInvisible(edgeRendering, !getBooleanValue(SHOW_REACTION_ORDER_EDGES));
            _kRenderingExtensions.getInvisible(edgeRendering).setPropagateToChildren(true);
            // TODO this does not work work with incremental update (https://github.com/kieler/KLighD/issues/37)
            // if (!getBooleanValue(SHOW_REACTION_ORDER_EDGES)) edge.initiallyHide()
            prevNode = node;
        }
    }
    _modeDiagrams.handleModes(nodes, reactorInstance);
    return nodes;
}
Also used : PortInstance(org.lflang.generator.PortInstance) ReactionInstance(org.lflang.generator.ReactionInstance) HashMap(java.util.HashMap) TimerInstance(org.lflang.generator.TimerInstance) ArrayList(java.util.ArrayList) KVector(org.eclipse.elk.core.math.KVector) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) HashSet(java.util.HashSet) Connection(org.lflang.lf.Connection) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) TriggerInstance(org.lflang.generator.TriggerInstance) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) LayerConstraint(org.eclipse.elk.alg.layered.options.LayerConstraint) LinkedList(java.util.LinkedList) KLabel(de.cau.cs.kieler.klighd.kgraph.KLabel) ReactorInstance(org.lflang.generator.ReactorInstance) ActionInstance(org.lflang.generator.ActionInstance) SendRange(org.lflang.generator.SendRange)

Example 2 with KVector

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

the class LayoutConfiguratorRegistry method getDefaultLayoutConfigurator.

public ISiriusWebLayoutConfigurator getDefaultLayoutConfigurator() {
    // @formatter:off
    SiriusWebLayoutConfigurator configurator = new SiriusWebLayoutConfigurator();
    configurator.configureByType(ELKDiagramConverter.DEFAULT_DIAGRAM_TYPE).setProperty(CoreOptions.ALGORITHM, LayeredOptions.ALGORITHM_ID).setProperty(CoreOptions.HIERARCHY_HANDLING, HierarchyHandling.INCLUDE_CHILDREN).setProperty(LayeredOptions.LAYERING_STRATEGY, LayeringStrategy.NETWORK_SIMPLEX).setProperty(LayeredOptions.SPACING_NODE_NODE, SPACING_NODE_NODE).setProperty(LayeredOptions.SPACING_NODE_NODE_BETWEEN_LAYERS, SPACING_NODE_NODE).setProperty(LayeredOptions.SPACING_EDGE_NODE, SPACING_NODE_EDGE).setProperty(LayeredOptions.SPACING_EDGE_NODE_BETWEEN_LAYERS, SPACING_NODE_EDGE);
    configurator.configureByType(NodeType.NODE_RECTANGLE).setProperty(CoreOptions.NODE_SIZE_CONSTRAINTS, SizeConstraint.free()).setProperty(CoreOptions.NODE_SIZE_OPTIONS, EnumSet.of(SizeOptions.ASYMMETRICAL)).setProperty(CoreOptions.NODE_SIZE_MINIMUM, new KVector(LayoutOptionValues.MIN_WIDTH_CONSTRAINT, LayoutOptionValues.MIN_HEIGHT_CONSTRAINT)).setProperty(CoreOptions.NODE_LABELS_PLACEMENT, NodeLabelPlacement.insideTopCenter()).setProperty(CoreOptions.NODE_SIZE_MINIMUM, new KVector(MIN_WIDTH_CONSTRAINT, MIN_HEIGHT_CONSTRAINT)).setProperty(CoreOptions.PORT_BORDER_OFFSET, DEFAULT_PORT_BORDER_OFFSET).setProperty(CoreOptions.PORT_LABELS_PLACEMENT, PortLabelPlacement.outside());
    configurator.configureByType(NodeType.NODE_LIST).setProperty(CoreOptions.ALGORITHM, FixedLayouterOptions.ALGORITHM_ID).setProperty(CoreOptions.NODE_LABELS_PLACEMENT, NodeLabelPlacement.insideTopCenter()).setProperty(CoreOptions.NODE_SIZE_FIXED_GRAPH_SIZE, true).setProperty(CoreOptions.PORT_BORDER_OFFSET, DEFAULT_PORT_BORDER_OFFSET);
    configurator.configureByType(NodeType.NODE_LIST_ITEM).setProperty(CoreOptions.NO_LAYOUT, true).setProperty(CoreOptions.NODE_LABELS_PADDING, new ElkPadding(0d, 12d, 0d, 6d));
    configurator.configureByType(NodeType.NODE_IMAGE).setProperty(CoreOptions.NODE_SIZE_CONSTRAINTS, EnumSet.of(SizeConstraint.MINIMUM_SIZE, SizeConstraint.PORT_LABELS, SizeConstraint.PORTS)).setProperty(CoreOptions.NODE_LABELS_PLACEMENT, NodeLabelPlacement.outsideTopCenter()).setProperty(CoreOptions.PORT_BORDER_OFFSET, DEFAULT_PORT_BORDER_OFFSET);
    // This image type does not match any diagram item. We add it to define the image size as constraint for the node image parent.
    configurator.configureByType(ELKDiagramConverter.DEFAULT_IMAGE_TYPE).setProperty(CoreOptions.NODE_SIZE_CONSTRAINTS, SizeConstraint.fixed());
    configurator.configure(ElkEdge.class).setProperty(CoreOptions.SPACING_EDGE_LABEL, 3d);
    return configurator;
}
Also used : KVector(org.eclipse.elk.core.math.KVector) ElkPadding(org.eclipse.elk.core.math.ElkPadding) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 3 with KVector

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

the class PortLabelPlacementCalculator method constrainedOutsidePortLabelPlacement.

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constrained Outside Port Labels
/**
 * Place the port label cells outside of the node in the knowledge that there might not be enough space to place
 * them without overlaps.
 */
private static void constrainedOutsidePortLabelPlacement(final NodeContext nodeContext, final PortSide portSide) {
    Collection<PortContext> portContexts = nodeContext.portContexts.get(portSide);
    // simply revert to simple port label placement
    if (portContexts.size() <= 2 || portSide == PortSide.EAST || portSide == PortSide.WEST) {
        simpleOutsidePortLabelPlacement(nodeContext, portSide);
        return;
    }
    // If space-efficient port labels are active, the leftmost / topmost port's label must be placed to its left /
    // above it
    boolean portWithSpecialNeeds = nodeContext.portLabelsPlacement.contains(PortLabelPlacement.SPACE_EFFICIENT);
    // Prepare things
    OverlapRemovalDirection overlapRemovalDirection = portSide == PortSide.NORTH ? OverlapRemovalDirection.UP : OverlapRemovalDirection.DOWN;
    VerticalLabelAlignment verticalLabelAlignment = portSide == PortSide.NORTH ? VerticalLabelAlignment.BOTTOM : VerticalLabelAlignment.TOP;
    // Obtain a rectangle strip overlap remover, which will actually do most of the work
    RectangleStripOverlapRemover overlapRemover = RectangleStripOverlapRemover.createForDirection(overlapRemovalDirection).withGap(nodeContext.portLabelSpacing);
    // Iterate over our ports and add rectangles to the overlap remover. Also, calculate the start coordinate
    double startCoordinate = portSide == PortSide.NORTH ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
    for (PortContext portContext : portContexts) {
        if (portContext.portLabelCell == null || !portContext.portLabelCell.hasLabels()) {
            continue;
        }
        KVector portSize = portContext.port.getSize();
        KVector portPosition = portContext.portPosition;
        LabelCell portLabelCell = portContext.portLabelCell;
        ElkRectangle portLabelCellRect = portLabelCell.getCellRectangle();
        // Setup the label cell's cell rectangle
        portLabelCellRect.width = portLabelCell.getMinimumWidth();
        portLabelCellRect.height = portLabelCell.getMinimumHeight();
        if (portWithSpecialNeeds) {
            portLabelCellRect.x = portPosition.x - portLabelCell.getMinimumWidth() - nodeContext.portLabelSpacing;
            portWithSpecialNeeds = false;
        } else {
            portLabelCellRect.x = portPosition.x + portSize.x + nodeContext.portLabelSpacing;
        }
        portLabelCell.setVerticalAlignment(verticalLabelAlignment);
        portLabelCell.setHorizontalAlignment(HorizontalLabelAlignment.RIGHT);
        // Add the rectangle to the overlap remover
        overlapRemover.addRectangle(portLabelCellRect);
        // Update start coordinate
        startCoordinate = portSide == PortSide.NORTH ? Math.min(startCoordinate, portPosition.y) : Math.max(startCoordinate, portPosition.y + portContext.port.getSize().y);
    }
    // The start coordinate needs to be offset by the port-label space
    startCoordinate += portSide == PortSide.NORTH ? -nodeContext.portLabelSpacing : nodeContext.portLabelSpacing;
    // Invoke the overlap remover
    overlapRemover.withStartCoordinate(startCoordinate).removeOverlaps();
    // We need to update the label cell's coordinates to be relative to the ports
    for (PortContext portContext : portContexts) {
        if (portContext.portLabelCell == null || !portContext.portLabelCell.hasLabels()) {
            continue;
        }
        ElkRectangle portLabelCellRect = portContext.portLabelCell.getCellRectangle();
        // Setup the label cell's cell rectangle
        portLabelCellRect.x -= portContext.portPosition.x;
        portLabelCellRect.y -= portContext.portPosition.y;
    }
}
Also used : RectangleStripOverlapRemover(org.eclipse.elk.alg.common.overlaps.RectangleStripOverlapRemover) LabelCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.LabelCell) VerticalLabelAlignment(org.eclipse.elk.alg.common.nodespacing.cellsystem.VerticalLabelAlignment) OverlapRemovalDirection(org.eclipse.elk.alg.common.overlaps.RectangleStripOverlapRemover.OverlapRemovalDirection) KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle) PortContext(org.eclipse.elk.alg.common.nodespacing.internal.PortContext)

Example 4 with KVector

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

the class PortPlacementCalculator method placeVerticalFixedRatioPorts.

/**
 * Places ports on the eastern and western side for the {@link PortConstraints#FIXED_RATIO} case.
 */
private static void placeVerticalFixedRatioPorts(final NodeContext nodeContext, final PortSide portSide) {
    final KVector nodeSize = nodeContext.nodeSize;
    for (PortContext portContext : nodeContext.portContexts.get(portSide)) {
        // The y coordinate is a function of the node's width and the port's position ratio
        portContext.portPosition.x = calculateVerticalPortXCoordinate(portContext, nodeSize.x);
        portContext.portPosition.y = nodeSize.y * portContext.port.getProperty(PORT_RATIO_OR_POSITION);
    }
}
Also used : KVector(org.eclipse.elk.core.math.KVector) PortContext(org.eclipse.elk.alg.common.nodespacing.internal.PortContext)

Example 5 with KVector

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

the class LabelPlacer method placeVerticalOuterNodeLabelContainer.

/**
 * Places a vertical outer node label container on the given side.
 */
private static void placeVerticalOuterNodeLabelContainer(final NodeContext nodeContext, final boolean outerNodeLabelsOverhang, final PortSide portSide) {
    KVector nodeSize = nodeContext.nodeSize;
    StripContainerCell nodeLabelContainer = nodeContext.outsideNodeLabelContainers.get(portSide);
    ElkRectangle nodeLabelContainerRect = nodeLabelContainer.getCellRectangle();
    // Set the container's width and height to its minimum width and height
    nodeLabelContainerRect.width = nodeLabelContainer.getMinimumWidth();
    nodeLabelContainerRect.height = nodeLabelContainer.getMinimumHeight();
    // The container must be at least as high as the node is
    nodeLabelContainerRect.height = Math.max(nodeLabelContainerRect.height, nodeSize.y);
    // If node labels are not allowed to overhang and if they would do so right now, make the container smaller
    if (nodeLabelContainerRect.height > nodeSize.y && !outerNodeLabelsOverhang) {
        nodeLabelContainerRect.height = nodeSize.y;
    }
    // Container's y coordinate
    nodeLabelContainerRect.y = -(nodeLabelContainerRect.height - nodeSize.y) / 2;
    // Container's x coordinate depends on whether we place the thing on the eastern or western side
    switch(portSide) {
        case WEST:
            nodeLabelContainerRect.x = -nodeLabelContainerRect.width;
            break;
        case EAST:
            nodeLabelContainerRect.x = nodeSize.x;
            break;
    }
    // Layout the container's children
    nodeLabelContainer.layoutChildrenHorizontally();
    nodeLabelContainer.layoutChildrenVertically();
}
Also used : KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle) StripContainerCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.StripContainerCell)

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