Browse Source

Tree layout is determined by BFS rather than DFS.

pull/15/head
mkonicek 15 years ago
parent
commit
bbf3053188
  1. 71
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayout.cs

71
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) void CalculateLayout(PositionedGraph positionedGraph)
{ {
HashSet<PositionedNode> seenNodes = new HashSet<PositionedNode>(); // impose a tree structure on the graph
HashSet<PositionedEdge> treeEdges = new HashSet<PositionedEdge>(); HashSet<PositionedEdge> treeEdges = DetermineTreeEdges(positionedGraph.Root);
// first layout pass // first layout pass
CalculateSubtreeSizes(positionedGraph.Root, seenNodes, treeEdges); CalculateSubtreeSizesRecursive(positionedGraph.Root, treeEdges);
// second layout pass // second layout pass
CalculateNodePosRecursive(positionedGraph.Root, treeEdges, MarginTop, MarginBottom); 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<PositionedNode> seenNodes, HashSet<PositionedEdge> treeEdges) HashSet<PositionedEdge> DetermineTreeEdges(PositionedNode root)
{ {
var treeEdges = new HashSet<PositionedEdge>();
var seenNodes = new HashSet<PositionedNode>();
var q = new Queue<PositionedNode>();
q.Enqueue(root);
seenNodes.Add(root); seenNodes.Add(root);
double subtreeSize = 0;
foreach (var property in root.Properties) { while (q.Count > 0) {
var edge = property.Edge; var node = q.Dequeue();
if (edge != null) { foreach (var property in node.Properties) {
var targetNode = edge.Target; var edge = property.Edge;
if (!seenNodes.Contains(targetNode)) { if (edge != null && edge.Target != null) {
// when we come to a node for the first time, we declare the incoming edge a tree edge if (!seenNodes.Contains(edge.Target)) {
treeEdges.Add(edge); treeEdges.Add(edge);
CalculateSubtreeSizes(targetNode, seenNodes, treeEdges); seenNodes.Add(edge.Target);
subtreeSize += targetNode.SubtreeSize; q.Enqueue(edge.Target);
}
} }
} }
} }
root.SubtreeSize = Math.Max(GetLateralSizeWithMargin(root), subtreeSize); return treeEdges;
} }
void CalculateSubtreeSizesRecursive(PositionedNode root, HashSet<PositionedEdge> 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);
}
/// <summary> /// <summary>
/// Given SubtreeSize for each node, positions the nodes, in a left-to-right or top-to-bottom layout. /// Given SubtreeSize for each node, positions the nodes, in a left-to-right or top-to-bottom layout.
/// </summary> /// </summary>
@ -133,39 +150,39 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
childLateral += child.SubtreeSize; childLateral += child.SubtreeSize;
} }
} }
IEnumerable<PositionedEdge> TreeEdges(PositionedNode node, HashSet<PositionedEdge> treeEdges) IEnumerable<PositionedEdge> TreeEdges(PositionedNode node, HashSet<PositionedEdge> treeEdges)
{ {
return node.Edges.Where(e => treeEdges.Contains(e)); return node.Edges.Where(e => treeEdges.Contains(e));
} }
IEnumerable<PositionedNode> TreeChildNodes(PositionedNode node, HashSet<PositionedEdge> treeEdges) IEnumerable<PositionedNode> TreeChildNodes(PositionedNode node, HashSet<PositionedEdge> treeEdges)
{ {
return TreeEdges(node, treeEdges).Select(e => e.Target); return TreeEdges(node, treeEdges).Select(e => e.Target);
} }
#region Horizontal / vertical layout helpers #region Horizontal / vertical layout helpers
double GetMainSizeWithMargin(PositionedNode node) double GetMainSizeWithMargin(PositionedNode node)
{ {
return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Width + NodeMarginH : node.Height + NodeMarginV; return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Width + NodeMarginH : node.Height + NodeMarginV;
} }
double GetLateralSizeWithMargin(PositionedNode node) double GetLateralSizeWithMargin(PositionedNode node)
{ {
return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Height + NodeMarginV : node.Width + NodeMarginH; return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Height + NodeMarginV : node.Width + NodeMarginH;
} }
double GetMain(PositionedNode node) double GetMain(PositionedNode node)
{ {
return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Left : node.Top; return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Left : node.Top;
} }
double GetLateral(PositionedNode node) double GetLateral(PositionedNode node)
{ {
return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Top : node.Left; return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Top : node.Left;
} }
void SetMain(PositionedNode node, double value) void SetMain(PositionedNode node, double value)
{ {
if (this.LayoutDirection == LayoutDirection.LeftRight) { if (this.LayoutDirection == LayoutDirection.LeftRight) {
@ -174,7 +191,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
node.Top = value; node.Top = value;
} }
} }
void SetLateral(PositionedNode node, double value) void SetLateral(PositionedNode node, double value)
{ {
if (this.LayoutDirection == LayoutDirection.LeftRight) { if (this.LayoutDirection == LayoutDirection.LeftRight) {
@ -183,7 +200,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
node.Left = value; node.Left = value;
} }
} }
#endregion #endregion
} }
} }

Loading…
Cancel
Save