/// <summary> /// Constructor. /// </summary> /// <param name="node"></param> public TreePlot(MCTSNodeStruct node) { rawRoot = node; //Stopwatch sw = Stopwatch.StartNew(); (root, treeInfo) = DrawTreeNode.Layout(node); //Console.WriteLine("Layout time in ms:"); //Console.WriteLine(sw.ElapsedMilliseconds); canvasHeight *= superSample; canvasWidth *= superSample; pointRadius *= superSample; edgeWidth *= superSample; leftMargin *= superSample; rightMargin *= superSample; topMargin *= superSample; bottomMargin *= superSample; rightHistogramWidth *= superSample; bottomHistogramHeight *= superSample; horisontalSpacing *= superSample; verticalSpacing *= superSample; titleMargin *= superSample; tickFontSize *= superSample; histogramTitleFontSize *= superSample; plotAreaHeight = canvasHeight - topMargin - bottomMargin - bottomHistogramHeight - verticalSpacing - titleMargin; plotAreaWidth = canvasWidth - leftMargin - rightMargin - rightHistogramWidth - 2 * horisontalSpacing; image = new Bitmap(canvasWidth / superSample, canvasHeight / superSample); Plot(); }
internal DrawTreeNode(DrawTreeNode parent, MCTSNodeStruct node, int depth, int siblingIndex, ref int identifier) { X = -1.0f; Y = (float)depth; id = identifier; BranchIndex = parent is null ? -1 : parent.BranchIndex != -1 ? parent.BranchIndex : siblingIndex; identifier++; Children = new List <DrawTreeNode>(); int childIndex = 0; // Sort children based on N so that heaviest subtree is always drawn leftmost. foreach (MCTSNodeStruct child in (from ind in Enumerable.Range(0, node.NumChildrenExpanded) select node.ChildAtIndexRef(ind)).OrderBy(c => - c.N)) { Children.Add(new DrawTreeNode(this, child, depth + 1, childIndex, ref identifier)); childIndex++; } Parent = parent; mod = 0.0f; change = 0.0f; shift = 0.0f; ancestor = this; lmostSibling = null; this.siblingIndex = siblingIndex; thread = null; }
internal DrawTreeNode LeftmostSibling() { if (lmostSibling is null && siblingIndex != 0) { lmostSibling = Parent.Children[0]; } return(lmostSibling); }
/// <summary> /// Calculate tree layout. /// </summary> internal static (DrawTreeNode, DrawTreeInfo) Layout(MCTSNodeStruct root) { DrawTreeInfo treeInfo = new DrawTreeInfo(); int id = 0; DrawTreeNode drawRoot = new DrawTreeNode(null, root, 0, 0, ref id); drawRoot.FirstWalk(); float min = drawRoot.SecondWalk(0.0f, float.MaxValue); float maxX = float.MinValue; float maxDepth = float.MinValue; List <int> nodesPerDepth = new List <int>(); // Shift whole tree so that min x is 0. drawRoot.ThirdWalk(-min, treeInfo); return(drawRoot, treeInfo); }
/// <summary> /// First tree walk (bottom-up) of Buckheim's layout algorithm. /// </summary> internal void FirstWalk() { if (Children.Count == 0) { X = siblingIndex != 0 ? LeftSibling().X + 1.0f : 0.0f; } else { DrawTreeNode defaultAncestor = Children[0]; foreach (DrawTreeNode child in Children) { child.FirstWalk(); defaultAncestor = child.Apportion(defaultAncestor); } ExecuteShifts(); float midPoint = (Children[0].X + Children[^ 1].X) / 2;
/// <summary> /// Draw edges and nodes of the search tree. /// </summary> /// <param name="node"></param> /// <param name="gfx"></param> /// <param name="penEdge"></param> /// <param name="brushRoot"></param> /// <param name="brushEven"></param> /// <param name="brushOdd"></param> internal void DrawTree(DrawTreeNode node, Graphics gfx, Pen penEdge, SolidBrush brushRoot, SolidBrush brushEven, SolidBrush brushOdd) { float x; float y; SolidBrush brush = node.BranchIndex == -1 ? brushRoot : node.BranchIndex % 2 == 0 ? brushEven : brushOdd; (x, y) = CanvasXY(node.X, node.Y); if (!(node.Parent is null)) { float xParent; float yParent; (xParent, yParent) = CanvasXY(node.Parent.X, node.Parent.Y); gfx.DrawLine(penEdge, x, y, xParent, yParent); } foreach (DrawTreeNode child in node.Children) { DrawTree(child, gfx, penEdge, brushRoot, brushEven, brushOdd); } DrawNode(x, y, gfx, brush); }