Esempio n. 1
0
        /// <summary>
        /// Handles the scenario where an overflow happens (the chosen leaf container is full).
        /// </summary>
        /// <remarks>
        /// It handles overflows by first trying to search for a suitable sibling under the same parent to insert the new leaf into.
        /// If this fails (either because there are no siblings, or because they are all full), it will split the node (or two
        /// nodes if there was at least one sibling) into 2 or 3 nodes, and distributes their children (and the new node) evenly amongst them.
        /// </remarks>
        /// <param name="node">The node where the overflow happened.</param>
        /// <param name="leaf">The leaf (or any new node if this is an internal level) to be inserted.</param>
        /// <returns>The newly created node if a split was inevitable.</returns>
        private HilbertNode HandleOverflow(HilbertNode node, HilbertNode leaf)
        {
            // check for a sibling node
            HilbertNode sibling = this.ChooseSibling(node);

            // then we redistribute these children evenly across the 2 or 3 nodes:
            // - between the original and its sibling if there was one, and it was not full
            // - between the original and a new node if there wasn't any sibling
            // - between the original, the sibling and the new node, if there was a sibling, but it was full
            // the original node is assumed to be always full here (hence the method name HandleOverflow)
            List <HilbertNode> distributionList = new List <HilbertNode>();
            HilbertNode        newNode          = null;

            distributionList.Add(node);
            if (sibling == null || sibling.IsFull)
            {
                newNode = new HilbertNode((HilbertNode)node.Parent);
                distributionList.Add(newNode);
            }

            if (sibling != null)
            {
                distributionList.Insert(sibling.LargestHilbertValue < node.LargestHilbertValue ? 0 : 1, sibling);
            }

            this.RedistributeChildrenEvenly(distributionList, leaf);

            return(newNode);
        }
Esempio n. 2
0
        /// <summary>
        /// Adjusts the tree ascending from the leaf level up to the root.
        /// </summary>
        /// <param name="node">The node where the overflow happened.</param>
        /// <param name="newNode">The new node, if a split was inevitable in <see cref="HandleOverflow(HilbertNode, HilbertNode)"/>, otherwise it's <c>null</c>.</param>
        /// <returns>The new <see cref="HilbertNode"/> on the root level, if the root node had to be split.</returns>
        private HilbertNode AdjustTree(HilbertNode node, HilbertNode newNode = null)
        {
            while (node != this.Root)
            {
                // propagate node split upward
                HilbertNode nParent = (HilbertNode)node.Parent;
                HilbertNode pParent = null;
                if (newNode != null)
                {
                    if (this.IsFull(nParent))
                    {
                        pParent = this.HandleOverflow(nParent, newNode);
                    }
                    else
                    {
                        nParent.AddChild(newNode);
                    }
                }

                // update MBR and LHV in parent level
                nParent.CorrectBounding();
                nParent.Children?.Sort(this.comparer);
                nParent.LargestHilbertValue =
                    nParent.ChildrenCount == 0 ? new BigInteger(-1) :
                    ((HilbertNode)nParent.Children[nParent.ChildrenCount - 1]).LargestHilbertValue;

                node    = nParent;
                newNode = pParent;
            }

            return(newNode);
        }
Esempio n. 3
0
        /// <summary>
        /// Chooses one the sibling for a node.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns>A sibling node of <c>node</c>.</returns>
        private HilbertNode ChooseSibling(HilbertNode node)
        {
            Tuple <HilbertNode, HilbertNode> siblings = this.ChooseSiblings(node);

            // prefer the sibling to the right side
            return(siblings.Item2 == null || siblings.Item2.IsFull ? siblings.Item1 : siblings.Item2);
        }
Esempio n. 4
0
        /// <summary>
        /// Adds a geometry by creating a new leaf node.
        /// </summary>
        /// <param name="geometry">The geometry to be added.</param>
        protected override void AddGeometry(IBasicGeometry geometry)
        {
            HilbertNode leaf          = new HilbertNode(geometry, this.GetHilbertValue(geometry));
            HilbertNode leafContainer = this.ChooseLeafContainer(leaf);

            if (leafContainer == this.Root && leafContainer.ChildrenCount == 0)
            {
                this.Height = 1;
            }

            HilbertNode newNode = null;

            if (!this.IsFull(leafContainer))
            {
                leafContainer.AddChild(leaf);
            }
            else
            {
                newNode = this.HandleOverflow(leafContainer, leaf);
            }

            HilbertNode rightRoot = this.AdjustTree(leafContainer, newNode);

            this.IncreaseHeight(rightRoot);
        }
Esempio n. 5
0
            /// <summary>
            /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
            /// </summary>
            /// <param name="x">The first object to compare.</param>
            /// <param name="y">The second object to compare.</param>
            /// <returns>
            /// A signed integer that indicates the relative values of <paramref name="x" /> and <paramref name="y" />, as shown in the following table.Value Meaning Less than zero<paramref name="x" /> is less than <paramref name="y" />.Zero<paramref name="x" /> equals <paramref name="y" />.Greater than zero<paramref name="x" /> is greater than <paramref name="y" />.
            /// </returns>
            public int Compare(Node x, Node y)
            {
                HilbertNode a = (HilbertNode)x;
                HilbertNode b = (HilbertNode)y;

                return(BigInteger.Compare(a.LargestHilbertValue, b.LargestHilbertValue));
            }
Esempio n. 6
0
        /// <summary>
        /// Increases the height when a split has propagated to the root node (in other words, the root node had to be split).
        /// </summary>
        /// <param name="rightRoot">The newly created sibling for the root node.</param>
        private void IncreaseHeight(HilbertNode rightRoot)
        {
            if (rightRoot == null)
            {
                return;
            }

            HilbertNode newRoot = new HilbertNode(this.MaxChildren);

            newRoot.AddChild(this.Root);
            newRoot.AddChild(rightRoot);
            this.Root = newRoot;
            this.Height++;
        }
Esempio n. 7
0
        /// <summary>
        /// Chooses the appropriate leaf container for a new leaf.
        /// </summary>
        /// <param name="leaf">The new leaf which shall be inserted to the tree.</param>
        /// <returns>The appropriate leaf container in which the new leaf shall be inserted.</returns>
        private HilbertNode ChooseLeafContainer(HilbertNode leaf)
        {
            Node node = this.Root;

            while (!node.IsLeafContainer)
            {
                HilbertNode lastChild = (HilbertNode)node.Children[node.ChildrenCount - 1];
                // select the child with the minimum LHV which is greater than "value"
                // if there are no such children, select the last child (the one with the greatest LHV)
                node = lastChild.LargestHilbertValue <= leaf.LargestHilbertValue ? lastChild :
                       node.Children.Find(n => ((HilbertNode)n).LargestHilbertValue > leaf.LargestHilbertValue);
            }

            return((HilbertNode)node);
        }
Esempio n. 8
0
        /// <summary>
        /// Handles the scenario where underflow happens by trying to redistribute the children of the node
        /// involved node between him and his siblings. If this fails, and the node has two siblings, it merges
        /// the node with its two siblings. In other cases we must let the underflow to happen.
        /// </summary>
        /// <param name="node">The node.</param>
        private void HandleUnderflow(HilbertNode node)
        {
            if (node == this.Root)
            {
                return;
            }

            if (node.ChildrenCount == 0)
            {
                node.Parent.RemoveChild(node);
                this.HandleUnderflow((HilbertNode)node.Parent);
                return;
            }

            if (node.ChildrenCount < this.MinChildren)
            {
                // check for sibling nodes
                Tuple <HilbertNode, HilbertNode> siblings = this.ChooseSiblings(node);
                if (this.HasSpareChild(siblings.Item1) || this.HasSpareChild(siblings.Item2))
                {
                    // if there are at least one sibling with more than the minimum amount of children, we redistribute
                    List <HilbertNode> distributionList = new List <HilbertNode>();
                    if (siblings.Item1 != null)
                    {
                        distributionList.Add(siblings.Item1);
                    }
                    distributionList.Add(node);
                    if (siblings.Item2 != null)
                    {
                        distributionList.Add(siblings.Item2);
                    }
                    this.RedistributeChildrenEvenly(distributionList);
                }
                else if (siblings.Item1 != null && siblings.Item2 != null)
                {
                    // if there are two siblings but both of the have the minimum number of children, we delete a node, then redistribute
                    List <HilbertNode> distributionList = new List <HilbertNode>();
                    distributionList.Add(siblings.Item1);
                    distributionList.Add(siblings.Item2);
                    List <HilbertNode> additionalChildren = new List <HilbertNode>();
                    node.Children.ForEach(child => additionalChildren.Add((HilbertNode)child));
                    node.Parent.RemoveChild(node);
                    this.RedistributeChildrenEvenly(distributionList, additionalChildren: additionalChildren);
                }
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Redistributes the children of the nodes specified evenly.
        /// </summary>
        /// <param name="nodes">The nodes whose children shall be redistributed evenly.</param>
        /// <param name="additionalChild">An optional additional child to be added.</param>
        /// <param name="additionalChildren">Optional additional children to be added.</param>
        private void RedistributeChildrenEvenly(List <HilbertNode> nodes, HilbertNode additionalChild = null, List <HilbertNode> additionalChildren = null)
        {
            List <HilbertNode> children = new List <HilbertNode>();

            nodes.ForEach(node =>
            {
                node?.Children?.ForEach(child => children.Add((HilbertNode)child));
            });

            if (additionalChild != null)
            {
                children.Add(additionalChild);
            }

            if (additionalChildren != null)
            {
                children.AddRange(additionalChildren);
            }

            children.Sort(this.comparer);

            nodes.ForEach(n => n.ClearChildren());
            Int32 distributionFactor             = Convert.ToInt32((decimal)children.Count / nodes.Count);
            IEnumerator <HilbertNode> enumerator = children.GetEnumerator();

            nodes.ForEach(container =>
            {
                for (Int32 i = 0; i < distributionFactor; i++)
                {
                    if (!enumerator.MoveNext())
                    {
                        break;
                    }
                    container.AddChild(enumerator.Current);
                }
            });
            if (enumerator.MoveNext())
            {
                nodes[nodes.Count - 1].AddChild(enumerator.Current);
            }
        }
Esempio n. 10
0
        /// <summary>
        /// Chooses two siblings (left and right) for a node.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns>A <see cref="Tuple"/> of two siblings (left and right) of <c>node</c>.</returns>
        private Tuple <HilbertNode, HilbertNode> ChooseSiblings(HilbertNode node)
        {
            if (node.Parent?.Children == null)
            {
                return(Tuple.Create <HilbertNode, HilbertNode>(null, null));
            }

            List <Node> siblings = node.Parent.Children;
            Int32       index    = siblings.IndexOf(node);

            HilbertNode left  = null;
            HilbertNode right = null;

            if (index + 1 < siblings.Count)
            {
                right = (HilbertNode)siblings[index + 1];
            }
            if (index > 0)
            {
                left = (HilbertNode)siblings[index - 1];
            }
            return(Tuple.Create <HilbertNode, HilbertNode>(left, right));
        }
Esempio n. 11
0
        /// <summary>
        /// Removes the specified geometry from the tree.
        /// </summary>
        /// <param name="geometry">The geometry.</param>
        /// <returns>
        ///   <c>true</c>, if the tree contains the geometry, otherwise, <c>false</c>.
        /// </returns>
        protected override Boolean RemoveGeometry(IBasicGeometry geometry)
        {
            // search for the leaf container which contains the specified geometry, if not found, return false
            Node l = null;

            this.FindLeafContainer(geometry, this.Root, ref l);
            if (l == null)
            {
                return(false);
            }

            // if found, remove the leaf with the specified geometry
            HilbertNode leafContainer = (HilbertNode)l;

            leafContainer.RemoveChild(
                leafContainer.Children.Find(child => child.Geometry == geometry));

            // then check for a potential underflow
            this.HandleUnderflow(leafContainer);

            // adjust parents
            this.AdjustTree(leafContainer);
            return(true);
        }
Esempio n. 12
0
 /// <summary>
 /// Utility function which determines whether the specified node is full.
 /// </summary>
 /// <remarks>
 /// It checks whether the node is the root node, because the root node can contain more children than all the other nodes.
 /// If its not the root node it just returns <c>node.IsFull</c>.
 /// </remarks>
 /// <param name="node">The node to be checked.</param>
 /// <returns>
 ///   <c>true</c> if the specified node is full; otherwise, <c>false</c>.
 /// </returns>
 private Boolean IsFull(HilbertNode node)
 {
     return(node == this.Root ? node.ChildrenCount == this.MinChildren * 2 : node.IsFull);
 }
Esempio n. 13
0
 /// <summary>
 /// Determines whether the specified node has a spare child, that is, whether or not it has more children than the minimum allowed.
 /// </summary>
 /// <param name="node">The node.</param>
 /// <returns>
 ///   <c>true</c> if the specified node has spare child, otherwise, <c>false</c>
 /// </returns>
 private Boolean HasSpareChild(HilbertNode node)
 {
     return(node != null && node.ChildrenCount > this.MinChildren);
 }
Esempio n. 14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="HilbertNode"/> class.
 /// This constructor creates a new leaf node.
 /// </summary>
 /// <param name="geometry">The geometry which shall be contained within this leaf.</param>
 /// <param name="hilbertValue">The hilbert value of <c>geometry</c>.</param>
 /// <param name="parent">
 ///     The parent node of this node (in this case a leaf container).
 ///     This is optional as the parent will be set when this node is added as a child to another <see cref="HilbertNode"/>.
 /// </param>
 public HilbertNode(IBasicGeometry geometry, BigInteger hilbertValue, HilbertNode parent = null)
     : base(geometry, parent)
 {
     this.LargestHilbertValue = hilbertValue;
 }
Esempio n. 15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="HilbertNode"/> class.
 /// This constructor creates a new internal node (non-root, and non-leaf).
 /// </summary>
 /// <param name="parent">The parent node of this node.</param>
 public HilbertNode(HilbertNode parent)
     : base(parent)
 {
     this.LargestHilbertValue = new BigInteger(-1);
 }