Search in sources :

Example 1 with KPort

use of de.cau.cs.kieler.klighd.kgraph.KPort in project lingua-franca by lf-lang.

the class InterfaceDependenciesVisualization method addInterfaceDependencies.

/**
 * Adds interface dependencies to the node if this option is active.
 * Visibility will be adjusted based on expansion state.
 */
public Spacing addInterfaceDependencies(KNode node, boolean expanded) {
    Spacing marginInit = null;
    if (getBooleanValue(SHOW_INTERFACE_DEPENDENCIES)) {
        List<Pair<KPort, KPort>> deps = getPortDependencies(node);
        if (!deps.isEmpty()) {
            for (Pair<KPort, KPort> pair : deps) {
                createDependencyEdge(pair, expanded);
            }
            // Fix content (label) of collapsed rendering
            KContainerRendering contentContainer = IterableExtensions.findFirst(Iterables.filter(node.getData(), KContainerRendering.class), it -> {
                return it.getProperty(KlighdProperties.COLLAPSED_RENDERING);
            });
            if (contentContainer != null) {
                if (!contentContainer.getProperty(LinguaFrancaShapeExtensions.REACTOR_CONTENT_CONTAINER)) {
                    contentContainer = IteratorExtensions.findFirst(Iterators.filter(contentContainer.eAllContents(), KContainerRendering.class), it -> {
                        return it.getProperty(LinguaFrancaShapeExtensions.REACTOR_CONTENT_CONTAINER);
                    });
                }
                if (contentContainer != null) {
                    List<KRendering> content = ImmutableList.copyOf(contentContainer.getChildren());
                    // Put into two new containers such that they are not centered/maximized
                    KRectangle firstContainer = _kContainerRenderingExtensions.addRectangle(contentContainer);
                    _kRenderingExtensions.setInvisible(firstContainer, true);
                    KRectangle secondContainer = _kContainerRenderingExtensions.addRectangle(firstContainer);
                    _kRenderingExtensions.setInvisible(secondContainer, true);
                    _kContainerRenderingExtensions.setGridPlacement(secondContainer, 1);
                    Iterables.addAll(secondContainer.getChildren(), content);
                    _kRenderingExtensions.setPointPlacementData(secondContainer, _kRenderingExtensions.LEFT, 0, 0.5f, _kRenderingExtensions.TOP, 0, 0, _kRenderingExtensions.H_CENTRAL, _kRenderingExtensions.V_TOP, 0, 0, 0, 0);
                    // Adjust ports separate dependency edges from label/content
                    if (content.size() > 0) {
                        marginInit = _utilityExtensions.getPortMarginsInitIfAbsent(node).add(new ElkMargin((content.size() * 20) - 8, 0, 0, 0));
                    }
                }
            }
        }
    }
    return marginInit;
}
Also used : CoreOptions(org.eclipse.elk.core.options.CoreOptions) Iterables(com.google.common.collect.Iterables) ElkMargin(org.eclipse.elk.core.math.ElkMargin) Spacing(org.eclipse.elk.core.math.Spacing) LinguaFrancaStyleExtensions(org.lflang.diagram.synthesis.styles.LinguaFrancaStyleExtensions) Inject(com.google.inject.Inject) Random(java.util.Random) Extension(org.eclipse.xtext.xbase.lib.Extension) AbstractSynthesisExtensions(org.lflang.diagram.synthesis.AbstractSynthesisExtensions) Iterators(com.google.common.collect.Iterators) KEdgeExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KEdgeExtensions) KContainerRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions) KRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions) KPolyline(de.cau.cs.kieler.klighd.krendering.KPolyline) LineStyle(de.cau.cs.kieler.klighd.krendering.LineStyle) ImmutableList(com.google.common.collect.ImmutableList) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) LinguaFrancaSynthesis(org.lflang.diagram.synthesis.LinguaFrancaSynthesis) DiagramSyntheses(de.cau.cs.kieler.klighd.syntheses.DiagramSyntheses) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KInvisibility(de.cau.cs.kieler.klighd.krendering.KInvisibility) SynthesisOption(de.cau.cs.kieler.klighd.SynthesisOption) Property(org.eclipse.elk.graph.properties.Property) KRenderingFactory(de.cau.cs.kieler.klighd.krendering.KRenderingFactory) Set(java.util.Set) KContainerRendering(de.cau.cs.kieler.klighd.krendering.KContainerRendering) LinguaFrancaShapeExtensions(org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions) Sets(com.google.common.collect.Sets) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) List(java.util.List) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) KlighdProperties(de.cau.cs.kieler.klighd.util.KlighdProperties) ViewSynthesisShared(de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) Pair(org.eclipse.xtext.xbase.lib.Pair) Spacing(org.eclipse.elk.core.math.Spacing) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KContainerRendering(de.cau.cs.kieler.klighd.krendering.KContainerRendering) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) Pair(org.eclipse.xtext.xbase.lib.Pair) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) ElkMargin(org.eclipse.elk.core.math.ElkMargin)

Example 2 with KPort

use of de.cau.cs.kieler.klighd.kgraph.KPort in project lingua-franca by lf-lang.

the class InterfaceDependenciesVisualization method getPortDependencies.

/**
 * Find dependencies between ports.
 */
private List<Pair<KPort, KPort>> getPortDependencies(KNode node) {
    Set<KPort> inputPorts = IterableExtensions.toSet(IterableExtensions.filter(node.getPorts(), it -> {
        return it.getProperty(LinguaFrancaSynthesis.REACTOR_INPUT);
    }));
    Set<KPort> outputPorts = IterableExtensions.toSet(IterableExtensions.filter(node.getPorts(), it -> {
        return it.getProperty(LinguaFrancaSynthesis.REACTOR_OUTPUT);
    }));
    // FIXME Replace with real logic
    Random rand = new Random();
    return IterableExtensions.toList(IterableExtensions.map(IterableExtensions.filter(Sets.cartesianProduct(inputPorts, outputPorts), it -> {
        return rand.nextBoolean();
    }), it -> {
        return new Pair<KPort, KPort>(it.get(0), it.get(1));
    }));
}
Also used : CoreOptions(org.eclipse.elk.core.options.CoreOptions) Iterables(com.google.common.collect.Iterables) ElkMargin(org.eclipse.elk.core.math.ElkMargin) Spacing(org.eclipse.elk.core.math.Spacing) LinguaFrancaStyleExtensions(org.lflang.diagram.synthesis.styles.LinguaFrancaStyleExtensions) Inject(com.google.inject.Inject) Random(java.util.Random) Extension(org.eclipse.xtext.xbase.lib.Extension) AbstractSynthesisExtensions(org.lflang.diagram.synthesis.AbstractSynthesisExtensions) Iterators(com.google.common.collect.Iterators) KEdgeExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KEdgeExtensions) KContainerRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions) KRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions) KPolyline(de.cau.cs.kieler.klighd.krendering.KPolyline) LineStyle(de.cau.cs.kieler.klighd.krendering.LineStyle) ImmutableList(com.google.common.collect.ImmutableList) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) LinguaFrancaSynthesis(org.lflang.diagram.synthesis.LinguaFrancaSynthesis) DiagramSyntheses(de.cau.cs.kieler.klighd.syntheses.DiagramSyntheses) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KInvisibility(de.cau.cs.kieler.klighd.krendering.KInvisibility) SynthesisOption(de.cau.cs.kieler.klighd.SynthesisOption) Property(org.eclipse.elk.graph.properties.Property) KRenderingFactory(de.cau.cs.kieler.klighd.krendering.KRenderingFactory) Set(java.util.Set) KContainerRendering(de.cau.cs.kieler.klighd.krendering.KContainerRendering) LinguaFrancaShapeExtensions(org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions) Sets(com.google.common.collect.Sets) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) List(java.util.List) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) KlighdProperties(de.cau.cs.kieler.klighd.util.KlighdProperties) ViewSynthesisShared(de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) Pair(org.eclipse.xtext.xbase.lib.Pair) Random(java.util.Random) KPort(de.cau.cs.kieler.klighd.kgraph.KPort)

Example 3 with KPort

use of de.cau.cs.kieler.klighd.kgraph.KPort 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 4 with KPort

use of de.cau.cs.kieler.klighd.kgraph.KPort in project lingua-franca by lf-lang.

the class CycleVisualization method detectAndHighlightCycles.

/**
 * Performs cycle detection based on the diagram's graph structure and applies given highlighting to the included elements
 */
public boolean detectAndHighlightCycles(ReactorInstance rootReactorInstance, Map<ReactorInstance, KNode> allReactorNodes, Consumer<KGraphElement> highlighter) {
    if (rootReactorInstance.hasCycles() && highlighter != null) {
        // Highlight cycles
        // A cycle consists of reactions and ports.
        HashMultimap<ReactorInstance, NamedInstance<?>> cycleElementsByReactor = HashMultimap.create();
        Set<NamedInstance<?>> cycles = rootReactorInstance.getCycles();
        for (NamedInstance<?> element : cycles) {
            // First find the involved reactor instances
            if (element instanceof ReactorInstance) {
                cycleElementsByReactor.put((ReactorInstance) element, element);
            } else {
                cycleElementsByReactor.put(element.getParent(), element);
            }
        }
        for (ReactorInstance reactor : cycleElementsByReactor.keySet()) {
            KNode node = allReactorNodes.get(reactor);
            if (node != null) {
                node.setProperty(DEPENDENCY_CYCLE, true);
                highlighter.accept(node);
                Set<NamedInstance<?>> reactorContentInCycle = cycleElementsByReactor.get(reactor);
                // Reactor edges
                for (KEdge edge : node.getOutgoingEdges()) {
                    if (connectsCycleElements(edge, cycles)) {
                        edge.setProperty(DEPENDENCY_CYCLE, true);
                        highlighter.accept(edge);
                    }
                }
                // Reactor ports
                for (KPort port : node.getPorts()) {
                    if (reactorContentInCycle.contains(NamedInstanceUtil.getLinkedInstance(port))) {
                        port.setProperty(DEPENDENCY_CYCLE, true);
                        highlighter.accept(port);
                    }
                }
                // Child Nodes
                for (KNode childNode : node.getChildren()) {
                    if (reactorContentInCycle.contains(NamedInstanceUtil.getLinkedInstance(childNode)) && !_utilityExtensions.sourceIsReactor(childNode)) {
                        childNode.setProperty(DEPENDENCY_CYCLE, true);
                        highlighter.accept(childNode);
                        for (KEdge edge : childNode.getOutgoingEdges()) {
                            if (connectsCycleElements(edge, cycles)) {
                                edge.setProperty(DEPENDENCY_CYCLE, true);
                                highlighter.accept(edge);
                            }
                        }
                    }
                }
            }
        }
        return true;
    }
    return false;
}
Also used : ReactorInstance(org.lflang.generator.ReactorInstance) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) NamedInstance(org.lflang.generator.NamedInstance)

Example 5 with KPort

use of de.cau.cs.kieler.klighd.kgraph.KPort in project lingua-franca by lf-lang.

the class LinguaFrancaSynthesis method transform.

// -------------------------------------------------------------------------
@Override
public KNode transform(final Model model) {
    KNode rootNode = _kNodeExtensions.createNode();
    try {
        // Find main
        Reactor main = IterableExtensions.findFirst(model.getReactors(), _utilityExtensions::isMainOrFederated);
        if (main != null) {
            ReactorInstance reactorInstance = new ReactorInstance(main, new SynthesisErrorReporter());
            rootNode.getChildren().addAll(createReactorNode(reactorInstance, true, null, null, new HashMap<>()));
        } else {
            KNode messageNode = _kNodeExtensions.createNode();
            _linguaFrancaShapeExtensions.addErrorMessage(messageNode, TEXT_NO_MAIN_REACTOR, null);
            rootNode.getChildren().add(messageNode);
        }
        // Show all reactors
        if (main == null || getBooleanValue(SHOW_ALL_REACTORS)) {
            List<KNode> reactorNodes = new ArrayList<>();
            for (Reactor reactor : model.getReactors()) {
                if (reactor == main)
                    continue;
                ReactorInstance reactorInstance = new ReactorInstance(reactor, new SynthesisErrorReporter(), new HashSet<>());
                reactorNodes.addAll(createReactorNode(reactorInstance, main == null, HashBasedTable.<ReactorInstance, PortInstance, KPort>create(), HashBasedTable.<ReactorInstance, PortInstance, KPort>create(), new HashMap<>()));
            }
            if (!reactorNodes.isEmpty()) {
                // To allow ordering, we need box layout but we also need layered layout for ports thus wrap all node
                // TODO use rect packing in the future
                reactorNodes.add(0, IterableExtensions.head(rootNode.getChildren()));
                int index = 0;
                for (KNode node : reactorNodes) {
                    if (node.getProperty(CoreOptions.COMMENT_BOX))
                        continue;
                    KNode child = _kNodeExtensions.createNode();
                    child.getChildren().add(node);
                    // Add comment nodes
                    for (KEdge edge : node.getIncomingEdges()) {
                        if (!edge.getSource().getProperty(CoreOptions.COMMENT_BOX))
                            continue;
                        child.getChildren().add(edge.getSource());
                    }
                    _kRenderingExtensions.addInvisibleContainerRendering(child);
                    setLayoutOption(child, CoreOptions.ALGORITHM, LayeredOptions.ALGORITHM_ID);
                    setLayoutOption(child, CoreOptions.PADDING, new ElkPadding(0));
                    // Order!
                    setLayoutOption(child, CoreOptions.PRIORITY, reactorNodes.size() - index);
                    rootNode.getChildren().add(child);
                    index++;
                }
                setLayoutOption(rootNode, CoreOptions.ALGORITHM, BoxLayouterOptions.ALGORITHM_ID);
                setLayoutOption(rootNode, CoreOptions.SPACING_NODE_NODE, 25.0);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        KNode messageNode = _kNodeExtensions.createNode();
        _linguaFrancaShapeExtensions.addErrorMessage(messageNode, "Error in Diagram Synthesis", e.getClass().getSimpleName() + " occurred. Could not create diagram.");
        rootNode.getChildren().add(messageNode);
    }
    return rootNode;
}
Also used : PortInstance(org.lflang.generator.PortInstance) SynthesisErrorReporter(org.lflang.diagram.synthesis.util.SynthesisErrorReporter) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) LayerConstraint(org.eclipse.elk.alg.layered.options.LayerConstraint) ReactorInstance(org.lflang.generator.ReactorInstance) Reactor(org.lflang.lf.Reactor) ElkPadding(org.eclipse.elk.core.math.ElkPadding)

Aggregations

KPort (de.cau.cs.kieler.klighd.kgraph.KPort)12 KEdge (de.cau.cs.kieler.klighd.kgraph.KEdge)9 KNode (de.cau.cs.kieler.klighd.kgraph.KNode)8 Pair (org.eclipse.xtext.xbase.lib.Pair)6 KRendering (de.cau.cs.kieler.klighd.krendering.KRendering)5 ElkMargin (org.eclipse.elk.core.math.ElkMargin)5 Iterables (com.google.common.collect.Iterables)4 SynthesisOption (de.cau.cs.kieler.klighd.SynthesisOption)4 KContainerRendering (de.cau.cs.kieler.klighd.krendering.KContainerRendering)4 KPolyline (de.cau.cs.kieler.klighd.krendering.KPolyline)4 KRectangle (de.cau.cs.kieler.klighd.krendering.KRectangle)4 LineStyle (de.cau.cs.kieler.klighd.krendering.LineStyle)4 ViewSynthesisShared (de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared)4 KContainerRenderingExtensions (de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions)4 KEdgeExtensions (de.cau.cs.kieler.klighd.krendering.extensions.KEdgeExtensions)4 KRenderingExtensions (de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions)4 KlighdProperties (de.cau.cs.kieler.klighd.util.KlighdProperties)4 ArrayList (java.util.ArrayList)4 HashMap (java.util.HashMap)4 KText (de.cau.cs.kieler.klighd.krendering.KText)3