Пример #1
0
        private bool approximate(KDTreeNode <T> current, double[] position,
                                 KDTreeNodeCollection <T> list, int maxLeaves, ref int visited)
        {
            // Compute distance from this node to the point
            double d = this.Distance(position, current.Position);

            list.Add(current, d);

            if (++visited > maxLeaves)
            {
                return(true);
            }


            // Check for leafs on the opposite sides of
            // the subtrees to nearest possible neighbors.

            // Prepare for recursion. The following null checks
            // will be used to avoid function calls if possible

            double value  = position[current.Axis];
            double median = current.Position[current.Axis];
            double u      = value - median;

            if (u <= 0)
            {
                if (current.Left != null)
                {
                    if (approximate(current.Left, position, list, maxLeaves, ref visited))
                    {
                        return(true);
                    }
                }

                if (current.Right != null && Math.Abs(u) <= list.Maximum)
                {
                    if (approximate(current.Right, position, list, maxLeaves, ref visited))
                    {
                        return(true);
                    }
                }
            }
            else
            {
                if (current.Right != null)
                {
                    approximate(current.Right, position, list, maxLeaves, ref visited);
                }

                if (current.Left != null && Math.Abs(u) <= list.Maximum)
                {
                    if (approximate(current.Left, position, list, maxLeaves, ref visited))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Пример #2
0
        /// <summary>
        ///   Returns an enumerator that iterates through the tree.
        /// </summary>
        ///
        /// <returns>
        ///   An <see cref="T:System.Collections.IEnumerator"/> object
        ///   that can be used to iterate through the collection.
        /// </returns>
        ///
        public virtual IEnumerator <KDTreeNode <T> > GetEnumerator()
        {
            if (Root == null)
            {
                yield break;
            }

            var stack = new Stack <KDTreeNode <T> >(new[] { Root });

            while (stack.Count != 0)
            {
                KDTreeNode <T> current = stack.Pop();

                yield return(current);

                if (current.Left != null)
                {
                    stack.Push(current.Left);
                }

                if (current.Right != null)
                {
                    stack.Push(current.Right);
                }
            }
        }
Пример #3
0
        /// <summary>
        ///   Creates the Root node for a new <see cref="KDTree{T}"/> given
        ///   a set of data points and their respective stored values.
        /// </summary>
        ///
        /// <param name="points">The data points to be inserted in the tree.</param>
        /// <param name="leaves">Return the number of leaves in the Root subtree.</param>
        /// <param name="inPlace">Whether the given <paramref name="points"/> vector
        ///   can be ordered in place. Passing true will change the original order of
        ///   the vector. If set to false, all operations will be performed on an extra
        ///   copy of the vector.</param>
        ///
        /// <returns>The Root node for a new <see cref="KDTree{T}"/>
        ///   contained the given <paramref name="points"/>.</returns>
        ///
        protected static KDTreeNode <T> CreateRoot(double[][] points, bool inPlace, out int leaves)
        {
            // Initial argument checks for creating the tree
            if (points == null)
            {
                throw new ArgumentNullException("points");
            }

            if (!inPlace)
            {
                points = (double[][])points.Clone();
            }

            leaves = 0;

            int dimensions = points[0].Length;

            // Create a comparer to compare individual array
            // elements at specified positions when sorting
            ElementComparer <double> comparer = new ElementComparer <double>();

            // Call the recursive algorithm to operate on the whole array (from 0 to points.Length)
            KDTreeNode <T> Root = create(points, 0, dimensions, 0, points.Length, comparer, ref leaves);

            // Create and return the newly formed tree
            return(Root);
        }
        /// <summary>
        ///   Attempts to add a value to the collection. If the list is full
        ///   and the value is more distant than the farthest node in the
        ///   collection, the value will not be added.
        /// </summary>
        ///
        /// <param name="value">The node to be added.</param>
        /// <param name="distance">The node distance.</param>
        ///
        /// <returns>Returns true if the node has been added; false otherwise.</returns>
        ///
        public bool AddFarthest(KDTreeNode <T> value, double distance)
        {
            // The list does have a limit. We have to check if the list
            // is already full or not, to see if we can discard or keep
            // the point

            if (count < Capacity)
            {
                // The list still has room for new elements.
                // Just add the value at the right position.

                add(distance, value);

                return(true); // a value has been added
            }

            // The list is at its maximum capacity. Check if the value
            // to be added is farther than the current nearest point.

            if (distance > Minimum)
            {
                // Yes, it is farther. Remove the previous nearest point
                // and insert this new one at an appropriate position to
                // keep the list ordered.

                RemoveNearest();

                add(distance, value);

                return(true); // a value has been added
            }

            // The value is even closer
            return(false); // discard it
        }
Пример #5
0
 /// <summary>
 ///   Creates a new <see cref="KDTree&lt;T&gt;"/>.
 /// </summary>
 ///
 /// <param name="dimension">The number of dimensions in the tree.</param>
 /// <param name="Root">The Root node, if already existent.</param>
 /// <param name="count">The number of elements in the Root node.</param>
 /// <param name="leaves">The number of leaves linked through the Root node.</param>
 ///
 public KDTree(int dimension, KDTreeNode <T> Root, int count, int leaves)
     : this(dimension)
 {
     this.Root   = Root;
     this.count  = count;
     this.leaves = leaves;
 }
Пример #6
0
        private KDTreeNode <T> insert(ref KDTreeNode <T> node, double[] position, int depth)
        {
            if (node == null)
            {
                // Base case: node is null
                return(node = new KDTreeNode <T>()
                {
                    Axis = depth % dimensions,
                    Position = position,
                });
            }
            else
            {
                KDTreeNode <T> newNode;

                // Recursive case: keep looking for a position to insert
                if (position[node.Axis] < node.Position[node.Axis])
                {
                    KDTreeNode <T> child = node.Left;
                    newNode   = insert(ref child, position, depth + 1);
                    node.Left = child;
                }
                else
                {
                    KDTreeNode <T> child = node.Right;
                    newNode    = insert(ref child, position, depth + 1);
                    node.Right = child;
                }

                return(newNode);
            }
        }
Пример #7
0
        /// <summary>
        ///   Inserts a value into the tree at the desired position.
        /// </summary>
        ///
        /// <param name="position">A double-vector with the same number of elements as dimensions in the tree.</param>
        ///
        protected KDTreeNode <T> AddNode(double[] position)
        {
            count++;
            var            root = Root;
            KDTreeNode <T> node = insert(ref root, position, 0);

            Root = root;
            return(node);
        }
        /// <summary>
        ///   Adds the specified item to the collection.
        /// </summary>
        ///
        /// <param name="distance">The distance from the node to the query point.</param>
        /// <param name="item">The item to be added.</param>
        ///
        private void add(double distance, KDTreeNode <T> item)
        {
            positions[count] = item;
            distances[count] = distance;
            count++;

            // Ensure it is in the right place.
            siftUpLast();
        }
Пример #9
0
        /// <summary>
        ///   Retrieves the nearest point to a given point.
        /// </summary>
        ///
        /// <param name="position">The queried point.</param>
        /// <param name="distance">The distance from the <paramref name="position"/>
        ///   to its nearest neighbor found in the tree.</param>
        ///
        /// <returns>A list of neighbor points, ordered by distance.</returns>
        ///
        public KDTreeNode <T> Nearest(double[] position, out double distance)
        {
            KDTreeNode <T> result = Root;

            distance = this.Distance(Root.Position, position);

            nearest(Root, position, ref result, ref distance);

            return(result);
        }
Пример #10
0
        // helper: get the right rectangle of node inside parent's rect
        private static Hyperrectangle rightRect(Hyperrectangle hyperrect, KDTreeNode <T> node)
        {
            //var rect = hyperrect.ToRectangle();
            //return (node.Axis != 0 ?
            //    Rectangle.FromLTRB(rect.Left, (int)node.Position[1], rect.Right, rect.Bottom) :
            //    Rectangle.FromLTRB((int)node.Position[0], rect.Top, rect.Right, rect.Bottom)).ToHyperrectangle();
            Hyperrectangle copy = new Hyperrectangle((double[])hyperrect.Min.Clone(), (double[])hyperrect.Max.Clone());

            copy.Min[node.Axis] = node.Position[node.Axis];
            return(copy);
        }
Пример #11
0
        /// <summary>
        ///   Creates a new <see cref="KDTree&lt;T&gt;"/>.
        /// </summary>
        ///
        /// <param name="dimension">The number of dimensions in the tree.</param>
        /// <param name="Root">The Root node, if already existent.</param>
        ///
        public KDTree(int dimension, KDTreeNode <T> Root)
            : this(dimension)
        {
            this.Root = Root;

            foreach (var node in this)
            {
                count++;

                if (node.IsLeaf)
                {
                    leaves++;
                }
            }
        }
Пример #12
0
        private void nearest(KDTreeNode <T> current, double[] position, ref KDTreeNode <T> match, ref double minDistance)
        {
            // Compute distance from this node to the point
            double d = this.Distance(position, current.Position);

            if (d < minDistance)
            {
                minDistance = d;
                match       = current;
            }

            // Check for leafs on the opposite sides of
            // the subtrees to nearest possible neighbors.

            // Prepare for recursion. The following null checks
            // will be used to avoid function calls if possible

            double value  = position[current.Axis];
            double median = current.Position[current.Axis];
            double u      = value - median;

            if (u <= 0)
            {
                if (current.Left != null)
                {
                    nearest(current.Left, position, ref match, ref minDistance);
                }

                if (current.Right != null && u <= minDistance)
                {
                    nearest(current.Right, position, ref match, ref minDistance);
                }
            }
            else
            {
                if (current.Right != null)
                {
                    nearest(current.Right, position, ref match, ref minDistance);
                }

                if (current.Left != null && u <= minDistance)
                {
                    nearest(current.Left, position, ref match, ref minDistance);
                }
            }
        }
Пример #13
0
        private IList <KDTreeNode <T> > getNodesInsideRegion(KDTreeNode <T> node, Hyperrectangle region, Hyperrectangle subRegion)
        {
            var result = new List <KDTreeNode <T> >();

            if (node != null && region.IntersectsWith(subRegion))
            {
                if (region.Contains(node.Position))
                {
                    result.Add(node);
                }

                result.AddRange(getNodesInsideRegion(node.Left, region, leftRect(subRegion, node)));
                result.AddRange(getNodesInsideRegion(node.Right, region, rightRect(subRegion, node)));
            }

            return(result);
        }
Пример #14
0
        /// <summary>
        ///   Radius search.
        /// </summary>
        ///
        private void nearest(KDTreeNode <T> current, double[] position,
                             double radius, ICollection <NodeDistance <KDTreeNode <T> > > list)
        {
            // Check if the distance of the point from this
            // node is within the desired radius, and if it
            // is, add to the list of nearest nodes.

            double d = this.Distance(position, current.Position);

            if (d <= radius)
            {
                list.Add(new NodeDistance <KDTreeNode <T> >(current, d));
            }

            // Prepare for recursion. The following null checks
            // will be used to avoid function calls if possible

            double value  = position[current.Axis];
            double median = current.Position[current.Axis];
            double u      = value - median;

            if (u <= 0)
            {
                if (current.Left != null)
                {
                    nearest(current.Left, position, radius, list);
                }

                if (current.Right != null && Math.Abs(u) <= radius)
                {
                    nearest(current.Right, position, radius, list);
                }
            }
            else
            {
                if (current.Right != null)
                {
                    nearest(current.Right, position, radius, list);
                }

                if (current.Left != null && Math.Abs(u) <= radius)
                {
                    nearest(current.Left, position, radius, list);
                }
            }
        }
Пример #15
0
        /// <summary>
        ///   k-nearest neighbors search.
        /// </summary>
        ///
        private void nearest(KDTreeNode <T> current, double[] position, KDTreeNodeCollection <T> list)
        {
            // Compute distance from this node to the point
            double d = this.Distance(position, current.Position);


            list.Add(current, d);


            // Check for leafs on the opposite sides of
            // the subtrees to nearest possible neighbors.

            // Prepare for recursion. The following null checks
            // will be used to avoid function calls if possible

            double value  = position[current.Axis];
            double median = current.Position[current.Axis];
            double u      = value - median;

            if (u <= 0)
            {
                if (current.Left != null)
                {
                    nearest(current.Left, position, list);
                }

                if (current.Right != null && Math.Abs(u) <= list.Maximum)
                {
                    nearest(current.Right, position, list);
                }
            }
            else
            {
                if (current.Right != null)
                {
                    nearest(current.Right, position, list);
                }

                if (current.Left != null && Math.Abs(u) <= list.Maximum)
                {
                    nearest(current.Left, position, list);
                }
            }
        }
Пример #16
0
 /// <summary>
 /// Indicates whether the current object is equal to another object of the same type.
 /// </summary>
 /// <param name="other">An object to compare with this object.</param>
 /// <returns>
 /// true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false.
 /// </returns>
 public bool Equals(KDTreeNode <T> other) // TODO: Try to remove IEquatable
 {
     return(this == other);
 }
Пример #17
0
 /// <summary>
 /// Compares the current object with another object of the same type.
 /// </summary>
 /// <param name="other">An object to compare with this object.</param>
 /// <returns>
 /// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other" /> parameter.Zero This object is equal to <paramref name="other" />. Greater than zero This object is greater than <paramref name="other" />.
 /// </returns>
 public int CompareTo(KDTreeNode <T> other)
 {
     return(this.Position[this.Axis].CompareTo(other.Position[other.Axis]));
 }