private void Expand(LayoutNode <T> lRoot, Dictionary <T, LayoutNode <T> > map)
        {
            map.Add(lRoot.Content, lRoot);
            var children = GetChildren(lRoot.Content).ToList();

            if (!children.Any())
            {
                return;
            }
            lRoot.Children = new List <LayoutNode <T> >(children.Count);
            for (int i = 0; i < children.Count; ++i)
            {
                var node = new LayoutNode <T> {
                    Content = children[i],
                    Number  = i,
                    Parent  = lRoot,
                    Level   = lRoot.Level + 1,
                    Width   = NodeWidth,
                    Height  = NodeHeight
                };
                node.Ancestor = node;
                lRoot.Children.Add(node);
                Expand(node, map);
            }
        }
        public IEnumerable <VisualTreeNode <T> > CalculateLayout(T root, float width, float height)
        {
            Dictionary <T, LayoutNode <T> > layoutNodeMap = new Dictionary <T, LayoutNode <T> >();
            var layoutRoot = new LayoutNode <T> {
                Content = root, Width = NodeWidth, Height = NodeHeight,
            };

            layoutRoot.Ancestor = layoutRoot;
            Expand(layoutRoot, layoutNodeMap);

            FirstWalk(layoutRoot);
            SecondWalk(layoutRoot, -layoutRoot.Prelim);
            NormalizeCoordinates(layoutNodeMap.Values);
            if (width > 0 && height > 0)
            {
                FitToBounds(width, height, layoutNodeMap.Values);
                Center(width, height, layoutNodeMap.Values);
            }

            return(layoutNodeMap.Values.Select(x => new VisualTreeNode <T>(x.Content)
            {
                Width = (int)Math.Round(x.Width),
                Height = (int)Math.Round(x.Height),
                X = (int)Math.Round(x.X),
                Y = (int)Math.Round(x.Y)
            }));
        }
        private LayoutNode <T> Ancestor(LayoutNode <T> u, LayoutNode <T> v)
        {
            var ancestor = u.Ancestor;

            if (ancestor == null)
            {
                return(null);
            }
            return(ancestor.Parent == v.Parent ? ancestor : null);
        }
 private void SecondWalk(LayoutNode <T> v, float m)
 {
     v.X = v.Prelim + m;
     v.Y = v.Level * (minVerticalSpacing + NodeHeight);
     if (v.IsLeaf)
     {
         return;
     }
     foreach (var child in v.Children)
     {
         SecondWalk(child, m + v.Mod);
     }
 }
        private void MoveSubtree(LayoutNode <T> wm, LayoutNode <T> wp, float shift)
        {
            int subtrees = wp.Number - wm.Number; // TODO: Investigate possible bug (if the value ever happens to be zero) - happens when the tree is actually a graph (but that's outside the use case of this algorithm which only works with trees)

            if (subtrees == 0)
            {
                throw new Exception("MoveSubtree failed: check if object is really a tree (no cycles)");
            }
            wp.Change -= shift / subtrees;
            wp.Shift  += shift;
            wm.Change += shift / subtrees;
            wp.Prelim += shift;
            wp.Mod    += shift;
        }
        private void Apportion(LayoutNode <T> v, ref LayoutNode <T> defaultAncestor)
        {
            var w = v.LeftSibling;

            if (w == null)
            {
                return;
            }
            LayoutNode <T> vip = v;
            LayoutNode <T> vop = v;
            LayoutNode <T> vim = w;
            LayoutNode <T> vom = vip.LeftmostSibling;

            float sip = vip.Mod;
            float sop = vop.Mod;
            float sim = vim.Mod;
            float som = vom.Mod;

            while (vim.NextRight != null && vip.NextLeft != null)
            {
                vim          = vim.NextRight;
                vip          = vip.NextLeft;
                vom          = vom.NextLeft;
                vop          = vop.NextRight;
                vop.Ancestor = v;
                float shift = (vim.Prelim + sim) - (vip.Prelim + sip) + minHorizontalSpacing + NodeWidth;
                if (shift > 0)
                {
                    var ancestor = Ancestor(vim, v) ?? defaultAncestor;
                    MoveSubtree(ancestor, v, shift);
                    sip += shift;
                    sop += shift;
                }
                sim += vim.Mod;
                sip += vip.Mod;
                som += vom.Mod;
                sop += vop.Mod;
            }
            if (vim.NextRight != null && vop.NextRight == null)
            {
                vop.Thread = vim.NextRight;
                vop.Mod   += (sim - sop);
            }
            if (vip.NextLeft != null && vom.NextLeft == null)
            {
                vom.Thread      = vip.NextLeft;
                vom.Mod        += (sip - som);
                defaultAncestor = v;
            }
        }
        private void ExecuteShifts(LayoutNode <T> v)
        {
            if (v.IsLeaf)
            {
                return;
            }
            float shift  = 0;
            float change = 0;

            for (int i = v.Children.Count - 1; i >= 0; --i)
            {
                var w = v.Children[i];
                w.Prelim += shift;
                w.Mod    += shift;
                change   += w.Change;
                shift    += (w.Shift + change);
            }
        }
        private void FirstWalk(LayoutNode <T> v)
        {
            LayoutNode <T> w;

            if (v.IsLeaf)
            {
                w = v.LeftSibling;
                if (w != null)
                {
                    v.Prelim = w.Prelim + minHorizontalSpacing + NodeWidth;
                }
            }
            else
            {
                var defaultAncestor = v.Children[0]; // leftmost child

                foreach (var child in v.Children)
                {
                    FirstWalk(child);
                    Apportion(child, ref defaultAncestor);
                }
                ExecuteShifts(v);
                var   leftmost  = v.Children.First();
                var   rightmost = v.Children.Last();
                float midPoint  = (leftmost.Prelim + rightmost.Prelim) / 2;
                w = v.LeftSibling;
                if (w != null)
                {
                    v.Prelim = w.Prelim + minHorizontalSpacing + NodeWidth;
                    v.Mod    = v.Prelim - midPoint;
                }
                else
                {
                    v.Prelim = midPoint;
                }
            }
        }