private Graph BuildVisualGraph()

in Sources/Visualization/Microsoft.Psi.Visualization.Windows/Views/Visuals2D/DiagnosticsVisualization/PipelineDiagnosticsVisualizationPresenter.cs [552:765]


        private Graph BuildVisualGraph(PipelineDiagnostics diagnostics, Dictionary<int, PipelineDiagnostics> pipelineIdToPipelineDiagnostics)
        {
            var subpipelineIdToPipelineDiagnostics = diagnostics.SubpipelineDiagnostics.ToDictionary(p => p.Id);
            var graph = new Graph($"{diagnostics.Name} (running={diagnostics.IsPipelineRunning})", $"g{diagnostics.Id}");
            switch (this.model.VisualizationObject.LayoutDirection)
            {
                case PipelineDiagnosticsVisualizationObject.GraphLayoutDirection.LeftToRight:
                    graph.Attr.LayerDirection = LayerDirection.LR;
                    break;
                case PipelineDiagnosticsVisualizationObject.GraphLayoutDirection.TopToBottom:
                    graph.Attr.LayerDirection = LayerDirection.TB;
                    break;
                case PipelineDiagnosticsVisualizationObject.GraphLayoutDirection.RightToLeft:
                    graph.Attr.LayerDirection = LayerDirection.RL;
                    break;
                case PipelineDiagnosticsVisualizationObject.GraphLayoutDirection.BottomToTop:
                    graph.Attr.LayerDirection = LayerDirection.BT;
                    break;
            }

            graph.UserData = diagnostics.Id;
            graph.Attr.BackgroundColor = Color.Transparent;
            var subpipelineNodes = new Dictionary<int, PipelineDiagnostics.PipelineElementDiagnostics>();
            var connectorsWithinSubpipelines = new Dictionary<int, PipelineDiagnostics.PipelineElementDiagnostics>();
            var statsSelector = this.StatsSelector(false);

            // add nodes
            foreach (var node in diagnostics.PipelineElements.Where(n => !this.IsConnectorBridge(n)))
            {
                var vis = this.BuildVisualNode(node);
                if (node.Kind == PipelineElementKind.Subpipeline && node.RepresentsSubpipeline != null)
                {
                    vis.UserData = node.RepresentsSubpipeline;
                    subpipelineNodes.Add(node.RepresentsSubpipeline.Id, node);
                    foreach (var n in node.RepresentsSubpipeline.PipelineElements.Where(n => n.Kind == PipelineElementKind.Connector))
                    {
                        connectorsWithinSubpipelines.Add(n.Id, n);
                    }
                }
                else if (node.Kind == PipelineElementKind.Connector)
                {
                    this.SetConnectorVisualAttributes(vis, node.Name);
                }

                graph.AddNode(vis);
            }

            // add connectors
            foreach (var node in diagnostics.PipelineElements.Where(this.IsConnectorBridge))
            {
                var connectsToSubpipeline = subpipelineNodes.ContainsKey(node.ConnectorBridgeToPipelineElement.PipelineId);
                if (!connectsToSubpipeline)
                {
                    if (!this.ShowExporterConnections && IsBridgeToExporter(node))
                    {
                        continue;
                    }

                    var connector = new Node($"n{node.Id}");
                    var bridgedPipeline = pipelineIdToPipelineDiagnostics[node.ConnectorBridgeToPipelineElement.PipelineId];
                    this.SetConnectorVisualAttributes(connector, $"{node.Name} ({bridgedPipeline.Name})");
                    graph.AddNode(connector);
                }
            }

            // add edges
            var selectedEdgeUpdated = false;
            foreach (var n in diagnostics.PipelineElements)
            {
                foreach (var i in n.Receivers)
                {
                    if (i.Source != null)
                    {
                        if (this.AddVisualEdge(i.Source.PipelineElement.Id, n.Id, i, graph, statsSelector))
                        {
                            selectedEdgeUpdated = true;
                        }
                    }
                }
            }

            // add connector bridge edges
            foreach (var n in diagnostics.PipelineElements.Where(this.IsConnectorBridge))
            {
                if (!this.ShowExporterConnections && IsBridgeToExporter(n))
                {
                    continue;
                }

                // connector bridging to subpipeline?
                if (subpipelineNodes.TryGetValue(n.ConnectorBridgeToPipelineElement.PipelineId, out PipelineDiagnostics.PipelineElementDiagnostics subNode))
                {
                    // edges from connector source directly to bridge target (subpipeline)
                    var sub = graph.FindNode($"n{subNode.Id}");
                    if (sub != null)
                    {
                        foreach (var i in n.Receivers)
                        {
                            if (i.Source != null)
                            {
                                var source = graph.FindNode($"n{i.Source.PipelineElement.Id}");
                                if (source != null)
                                {
                                    if (this.AddVisualEdge(source, sub, i, graph, statsSelector))
                                    {
                                        selectedEdgeUpdated = true;
                                    }
                                }
                            }
                        }

                        // edges from connector bridge source (subpipeline) to connector targets
                        foreach (var o in n.Emitters)
                        {
                            foreach (var t in o.Targets)
                            {
                                var target = graph.FindNode($"n{t.PipelineElement.Id}");
                                if (target != null)
                                {
                                    if (this.AddVisualEdge(sub, target, t, graph, statsSelector))
                                    {
                                        selectedEdgeUpdated = true;
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    // connector bridging graphs
                    var bridgedPipeline = pipelineIdToPipelineDiagnostics[n.ConnectorBridgeToPipelineElement.PipelineId];
                    var connector = graph.FindNode($"n{n.Id}");

                    // add dotted line edge representing connector bridged to descendant pipeline
                    var targetPipeline = bridgedPipeline;
                    while (targetPipeline != null)
                    {
                        if (subpipelineIdToPipelineDiagnostics.ContainsKey(targetPipeline.Id))
                        {
                            var targetNode = graph.FindNode($"n{subpipelineNodes[targetPipeline.Id].Id}");
                            graph.AddPrecalculatedEdge(this.BuildVisualEdge(connector, targetNode, n.Name, bridgedPipeline.Name, -1, string.Empty, string.Empty, Style.Dotted));
                            break;
                        }

                        // walk up ancestor chain until we're at a direct child subpipeline
                        targetPipeline = targetPipeline.ParentPipelineDiagnostics;
                    }
                }
            }

            // add connector bridge edges between descendants (shown between current-level subpiplines)
            int? TryFindCurrentLevelAncestorSubpipelineId(int id)
            {
                foreach (var ancestor in pipelineIdToPipelineDiagnostics[id].AncestorPipelines)
                {
                    if (subpipelineNodes.TryGetValue(ancestor.Id, out PipelineDiagnostics.PipelineElementDiagnostics subpipeline))
                    {
                        return subpipeline.Id;
                    }
                }

                return null;
            }

            foreach (var descendantConnector in diagnostics.GetAllPipelineElementDiagnostics().Where(this.IsConnectorBridge))
            {
                if (descendantConnector.Emitters.Length == 0 /* source-side of connector pair */)
                {
                    var sourceId = descendantConnector.PipelineId;
                    var targetId = descendantConnector.ConnectorBridgeToPipelineElement.PipelineId;
                    var sourceCurrentLevelId = TryFindCurrentLevelAncestorSubpipelineId(sourceId);
                    var targetCurrentLevelId = TryFindCurrentLevelAncestorSubpipelineId(targetId);
                    if (sourceCurrentLevelId != null && targetCurrentLevelId != null && sourceCurrentLevelId != targetCurrentLevelId)
                    {
                        var sourceNode = graph.FindNode($"n{sourceCurrentLevelId}");
                        var targetNode = graph.FindNode($"n{targetCurrentLevelId}");
                        graph.AddPrecalculatedEdge(this.BuildVisualEdge(sourceNode, targetNode, string.Empty, descendantConnector.Name, -1, string.Empty, string.Empty, Style.Dotted));
                    }
                }
            }

            // add direct connections from one subpipeline (connector) to another
            foreach (var c in connectorsWithinSubpipelines.Values)
            {
                if (c.ConnectorBridgeToPipelineElement != null)
                {
                    if (c.ConnectorBridgeToPipelineElement.PipelineId == diagnostics.Id && c.ConnectorBridgeToPipelineElement.Receivers.Length == 1)
                    {
                        var i = c.ConnectorBridgeToPipelineElement.Receivers[0];
                        if (i.Source != null && i.Source.PipelineElement.PipelineId == diagnostics.Id && i.Source.PipelineElement.ConnectorBridgeToPipelineElement != null)
                        {
                            if (subpipelineNodes.TryGetValue(i.Source.PipelineElement.ConnectorBridgeToPipelineElement.PipelineId, out PipelineDiagnostics.PipelineElementDiagnostics source) &&
                                subpipelineNodes.TryGetValue(c.PipelineId, out PipelineDiagnostics.PipelineElementDiagnostics target))
                            {
                                if (this.AddVisualEdge(source.Id, target.Id, i, graph, statsSelector))
                                {
                                    selectedEdgeUpdated = true;
                                }
                            }
                        }
                    }
                }
            }

            if (!selectedEdgeUpdated && this.model.SelectedEdgeId != -1)
            {
                // hide while in subpipeline
                this.model.SelectedEdgeDetails = string.Empty;
            }

            this.VisualizeEdgeColoring(graph);
            return graph;
        }