diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayout.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayout.cs index e6eeda03b0..ae18c64eff 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayout.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayout.cs @@ -78,35 +78,52 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout void CalculateLayout(PositionedGraph positionedGraph) { - HashSet seenNodes = new HashSet(); - HashSet treeEdges = new HashSet(); + // impose a tree structure on the graph + HashSet treeEdges = DetermineTreeEdges(positionedGraph.Root); // first layout pass - CalculateSubtreeSizes(positionedGraph.Root, seenNodes, treeEdges); + CalculateSubtreeSizesRecursive(positionedGraph.Root, treeEdges); // second layout pass CalculateNodePosRecursive(positionedGraph.Root, treeEdges, MarginTop, MarginBottom); } - // determines which edges are tree edges, and calculates subtree size for each node - private void CalculateSubtreeSizes(PositionedNode root, HashSet seenNodes, HashSet treeEdges) + + HashSet DetermineTreeEdges(PositionedNode root) { + var treeEdges = new HashSet(); + + var seenNodes = new HashSet(); + var q = new Queue(); + q.Enqueue(root); seenNodes.Add(root); - double subtreeSize = 0; - foreach (var property in root.Properties) { - var edge = property.Edge; - if (edge != null) { - var targetNode = edge.Target; - if (!seenNodes.Contains(targetNode)) { - // when we come to a node for the first time, we declare the incoming edge a tree edge - treeEdges.Add(edge); - CalculateSubtreeSizes(targetNode, seenNodes, treeEdges); - subtreeSize += targetNode.SubtreeSize; + + while (q.Count > 0) { + var node = q.Dequeue(); + foreach (var property in node.Properties) { + var edge = property.Edge; + if (edge != null && edge.Target != null) { + if (!seenNodes.Contains(edge.Target)) { + treeEdges.Add(edge); + seenNodes.Add(edge.Target); + q.Enqueue(edge.Target); + } } } } - root.SubtreeSize = Math.Max(GetLateralSizeWithMargin(root), subtreeSize); + return treeEdges; } - + void CalculateSubtreeSizesRecursive(PositionedNode root, HashSet treeEdges) + { + double subtreeSize = 0; + foreach (var child in TreeChildNodes(root, treeEdges)) { + CalculateSubtreeSizesRecursive(child, treeEdges); + // just sum up the sizes of children + subtreeSize += child.SubtreeSize; + } + root.SubtreeSize = Math.Max(GetLateralSizeWithMargin(root), subtreeSize); + } + + /// /// Given SubtreeSize for each node, positions the nodes, in a left-to-right or top-to-bottom layout. /// @@ -133,39 +150,39 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout childLateral += child.SubtreeSize; } } - + IEnumerable TreeEdges(PositionedNode node, HashSet treeEdges) { return node.Edges.Where(e => treeEdges.Contains(e)); } - + IEnumerable TreeChildNodes(PositionedNode node, HashSet treeEdges) { return TreeEdges(node, treeEdges).Select(e => e.Target); } - + #region Horizontal / vertical layout helpers - + double GetMainSizeWithMargin(PositionedNode node) { return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Width + NodeMarginH : node.Height + NodeMarginV; } - + double GetLateralSizeWithMargin(PositionedNode node) { return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Height + NodeMarginV : node.Width + NodeMarginH; } - + double GetMain(PositionedNode node) { return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Left : node.Top; } - + double GetLateral(PositionedNode node) { return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Top : node.Left; } - + void SetMain(PositionedNode node, double value) { if (this.LayoutDirection == LayoutDirection.LeftRight) { @@ -174,7 +191,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout node.Top = value; } } - + void SetLateral(PositionedNode node, double value) { if (this.LayoutDirection == LayoutDirection.LeftRight) { @@ -183,7 +200,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout node.Left = value; } } - + #endregion } }