/// <summary>
        /// Splits the given node in two other nodes.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="minimumSize"></param>
        /// <returns></returns>
        private static Node[] SplitNode(Node node, int minimumSize)
        {
            bool leaf = (node.Children is List <T>);

            // create the target nodes.
            var nodes = new Node[2];

            nodes[0]       = new Node();
            nodes[0].Boxes = new List <BoxF2D>();
            if (leaf)
            {
                nodes[0].Children = new List <T>();
            }
            else
            {
                nodes[0].Children = new List <Node>();
            }
            nodes[1]       = new Node();
            nodes[1].Boxes = new List <BoxF2D>();
            if (leaf)
            {
                nodes[1].Children = new List <T>();
            }
            else
            {
                nodes[1].Children = new List <Node>();
            }

            // select the seed boxes.
            int[] seeds = RTreeMemoryIndex <T> .SelectSeeds(node.Boxes);

            // add the boxes.
            nodes[0].Boxes.Add(node.Boxes[seeds[0]]);
            nodes[1].Boxes.Add(node.Boxes[seeds[1]]);
            nodes[0].Children.Add(node.Children[seeds[0]]);
            nodes[1].Children.Add(node.Children[seeds[1]]);

            // create the boxes.
            var boxes = new BoxF2D[2]
            {
                node.Boxes[seeds[0]], node.Boxes[seeds[1]]
            };

            node.Boxes.RemoveAt(seeds[0]); // seeds[1] is always < seeds[0].
            node.Boxes.RemoveAt(seeds[1]);
            node.Children.RemoveAt(seeds[0]);
            node.Children.RemoveAt(seeds[1]);

            while (node.Boxes.Count > 0)
            {
                // check if one of them needs em all!
                if (nodes[0].Boxes.Count + node.Boxes.Count == minimumSize)
                { // all remaining boxes need te be assigned here.
                    for (int idx = 0; node.Boxes.Count > 0; idx++)
                    {
                        boxes[0] = boxes[0].Union(node.Boxes[0]);
                        nodes[0].Boxes.Add(node.Boxes[0]);
                        nodes[0].Children.Add(node.Children[0]);

                        node.Boxes.RemoveAt(0);
                        node.Children.RemoveAt(0);
                    }
                }
                else if (nodes[1].Boxes.Count + node.Boxes.Count == minimumSize)
                { // all remaining boxes need te be assigned here.
                    for (int idx = 0; node.Boxes.Count > 0; idx++)
                    {
                        boxes[1] = boxes[1].Union(node.Boxes[0]);
                        nodes[1].Boxes.Add(node.Boxes[0]);
                        nodes[1].Children.Add(node.Children[0]);

                        node.Boxes.RemoveAt(0);
                        node.Children.RemoveAt(0);
                    }
                }
                else
                { // choose one of the leaves.
                    int leafIdx;
                    int nextId = RTreeMemoryIndex <T> .PickNext(boxes, node.Boxes, out leafIdx);

                    boxes[leafIdx] = boxes[leafIdx].Union(node.Boxes[nextId]);

                    nodes[leafIdx].Boxes.Add(node.Boxes[nextId]);
                    nodes[leafIdx].Children.Add(node.Children[nextId]);

                    node.Boxes.RemoveAt(nextId);
                    node.Children.RemoveAt(nextId);
                }
            }

            RTreeMemoryIndex <T> .SetParents(nodes[0]);

            RTreeMemoryIndex <T> .SetParents(nodes[1]);

            return(nodes);
        }
        /// <summary>
        /// Adds the given item to the given box.
        /// </summary>
        /// <param name="leaf"></param>
        /// <param name="box"></param>
        /// <param name="item"></param>
        /// <param name="minimumSize"></param>
        /// <param name="maximumSize"></param>
        private static Node Add(Node leaf, BoxF2D box, T item, int minimumSize, int maximumSize)
        {
            if (box == null)
            {
                throw new ArgumentNullException("box");
            }
            if (leaf == null)
            {
                throw new ArgumentNullException("leaf");
            }

            Node ll = null;

            if (leaf.Boxes.Count == maximumSize)
            { // split the node.
                // add the child.
                leaf.Boxes.Add(box);
                leaf.Children.Add(item);

                Node[] split = RTreeMemoryIndex <T> .SplitNode(leaf, minimumSize);

                leaf.Boxes    = split[0].Boxes;
                leaf.Children = split[0].Children;
                RTreeMemoryIndex <T> .SetParents(leaf);

                ll = split[1];
            }
            else
            {
                // add the child.
                leaf.Boxes.Add(box);
                leaf.Children.Add(item);
            }

            // adjust the tree.
            Node n  = leaf;
            Node nn = ll;

            while (n.Parent != null)
            {                                           // keep going until the root is reached.
                Node p = n.Parent;
                RTreeMemoryIndex <T> .TightenFor(p, n); // tighten the parent box around n.

                if (nn != null)
                {     // propagate split if needed.
                    if (p.Boxes.Count == maximumSize)
                    { // parent needs to be split.
                        p.Boxes.Add(nn.GetBox());
                        p.Children.Add(nn);
                        Node[] split = RTreeMemoryIndex <T> .SplitNode(
                            p, minimumSize);

                        p.Boxes    = split[0].Boxes;
                        p.Children = split[0].Children;
                        RTreeMemoryIndex <T> .SetParents(p);

                        nn = split[1];
                    }
                    else
                    { // add the other 'split' node.
                        p.Boxes.Add(nn.GetBox());
                        p.Children.Add(nn);
                        nn.Parent = p;
                        nn        = null;
                    }
                }
                n = p;
            }
            if (nn != null)
            { // create a new root node and
                var root = new Node();
                root.Boxes = new List <BoxF2D>();
                root.Boxes.Add(n.GetBox());
                root.Boxes.Add(nn.GetBox());
                root.Children = new List <Node>();
                root.Children.Add(n);
                n.Parent = root;
                root.Children.Add(nn);
                nn.Parent = root;
                return(root);
            }
            return(null); // no new root node needed.
        }