Example #1
0
        /// <summary>
        /// Find KD-tree nodes whose keys are <I>n</I> nearest neighbors to
        /// key. Uses algorithm above.  Neighbors are returned in ascending
        /// order of distance to key.
        /// </summary>
        /// <param name="key">key for KD-tree node</param>
        /// <param name="numNeighbors">The Integer showing how many neighbors to find</param>
        /// <returns>An array of objects at the node nearest to the key</returns>
        /// <exception cref="KeySizeException">Mismatch if key length doesn't match the dimension for the tree</exception>
        /// <exception cref="NeighborsOutOfRangeException">if <I>n</I> is negative or exceeds tree size </exception>
        public object[] Nearest(double[] key, int numNeighbors)
        {
            if (numNeighbors < 0 || numNeighbors > _count)
            {
                throw new NeighborsOutOfRangeException();
            }

            if (key.Length != _k)
            {
                throw new KeySizeException();
            }

            object[]            neighbors = new object[numNeighbors];
            NearestNeighborList nnl       = new NearestNeighborList(numNeighbors);

            // initial call is with infinite hyper-rectangle and max distance
            HRect        hr         = HRect.InfiniteHRect(key.Length);
            const double maxDistSqd = 1.79769e+30;
            HPoint       keyp       = new HPoint(key);

            KdNode.Nnbr(_root, keyp, hr, maxDistSqd, 0, _k, nnl);

            for (int i = 0; i < numNeighbors; ++i)
            {
                KdNode kd = (KdNode)nnl.RemoveHighest();
                neighbors[numNeighbors - i - 1] = kd.V;
            }

            return(neighbors);
        }
Example #2
0
        /// <summary>
        /// Method Nearest Neighbor from Andrew Moore's thesis. Numbered
        /// comments are direct quotes from there. Step "SDL" is added to
        /// make the algorithm work correctly.  NearestNeighborList solution
        /// courtesy of Bjoern Heckel.
        /// </summary>
        /// <param name="kd"></param>
        /// <param name="target"></param>
        /// <param name="hr"></param>
        /// <param name="maxDistSqd"></param>
        /// <param name="lev"></param>
        /// <param name="k"></param>
        /// <param name="nnl"></param>
        public static void Nnbr(KdNode kd, HPoint target, HRect hr,
                                double maxDistSqd, int lev, int k,
                                NearestNeighborList nnl)
        {
            // 1. if kd is empty then set dist-sqd to infinity and exit.
            if (kd == null)
            {
                return;
            }

            // 2. s := split field of kd
            int s = lev % k;

            // 3. pivot := dom-elt field of kd
            HPoint pivot         = kd.K;
            double pivotToTarget = HPoint.SquareDistance(pivot, target);

            // 4. Cut hr into to sub-hyperrectangles left-hr and right-hr.
            //    The cut plane is through pivot and perpendicular to the s
            //    dimension.
            HRect leftHr  = hr; // optimize by not cloning
            HRect rightHr = hr.Copy();

            leftHr.Max[s]  = pivot[s];
            rightHr.Min[s] = pivot[s];

            // 5. target-in-left := target_s <= pivot_s
            bool targetInLeft = target[s] < pivot[s];

            KdNode nearerKd;
            HRect  nearerHr;
            KdNode furtherKd;
            HRect  furtherHr;

            if (targetInLeft)
            {
                // 6. if target-in-left then
                //    6.1. nearer-kd := left field of kd and nearer-hr := left-hr
                //    6.2. further-kd := right field of kd and further-hr := right-hr
                nearerKd  = kd.Left;
                nearerHr  = leftHr;
                furtherKd = kd.Right;
                furtherHr = rightHr;
            }
            else
            {
                //
                // 7. if not target-in-left then
                //    7.1. nearer-kd := right field of kd and nearer-hr := right-hr
                //    7.2. further-kd := left field of kd and further-hr := left-hr
                nearerKd  = kd.Right;
                nearerHr  = rightHr;
                furtherKd = kd.Left;
                furtherHr = leftHr;
            }

            // 8. Recursively call Nearest Neighbor with paramters
            //    (nearer-kd, target, nearer-hr, max-dist-sqd), storing the
            //    results in nearest and dist-sqd
            Nnbr(nearerKd, target, nearerHr, maxDistSqd, lev + 1, k, nnl);

            double distSqd;

            if (!nnl.IsCapacityReached)
            {
                distSqd = 1.79769e+30; // Double.MaxValue;
            }
            else
            {
                distSqd = nnl.MaxPriority;
            }

            // 9. max-dist-sqd := minimum of max-dist-sqd and dist-sqd
            maxDistSqd = Math.Min(maxDistSqd, distSqd);

            // 10. A nearer point could only lie in further-kd if there were some
            //     part of further-hr within distance sqrt(max-dist-sqd) of
            //     target.  If this is the case then
            HPoint closest = furtherHr.Closest(target);

            if (HPoint.EuclideanDistance(closest, target) < Math.Sqrt(maxDistSqd))
            {
                // 10.1 if (pivot-target)^2 < dist-sqd then
                if (pivotToTarget < distSqd)
                {
                    // 10.1.1 nearest := (pivot, range-elt field of kd)

                    // 10.1.2 dist-sqd = (pivot-target)^2
                    distSqd = pivotToTarget;

                    // add to nnl
                    if (!kd.IsDeleted)
                    {
                        nnl.Insert(kd, distSqd);
                    }

                    // 10.1.3 max-dist-sqd = dist-sqd
                    // max_dist_sqd = dist_sqd;
                    if (nnl.IsCapacityReached)
                    {
                        maxDistSqd = nnl.MaxPriority;
                    }
                    else
                    {
                        maxDistSqd = 1.79769e+30; //Double.MaxValue;
                    }
                }

                // 10.2 Recursively call Nearest Neighbor with parameters
                //      (further-kd, target, further-hr, max-dist_sqd),
                //      storing results in temp-nearest and temp-dist-sqd
                Nnbr(furtherKd, target, furtherHr, maxDistSqd, lev + 1, k, nnl);
                double tempDistSqd = nnl.MaxPriority;

                // 10.3 If tmp-dist-sqd < dist-sqd then
                if (tempDistSqd < distSqd)
                {
                    // 10.3.1 nearest := temp_nearest and dist_sqd := temp_dist_sqd
                    distSqd = tempDistSqd;
                }
            }
            else if (pivotToTarget < maxDistSqd)
            {
                // SDL: otherwise, current point is nearest
                distSqd = pivotToTarget;
            }
        }
Example #3
0
        /// <summary>
        /// Find KD-tree nodes whose keys are <I>n</I> nearest neighbors to
        /// key. Uses algorithm above.  Neighbors are returned in ascending
        /// order of distance to key.
        /// </summary>
        /// <param name="key">key for KD-tree node</param>
        /// <param name="numNeighbors">The Integer showing how many neighbors to find</param>
        /// <returns>An array of objects at the node nearest to the key</returns>
        /// <exception cref="KeySizeException">Mismatch if key length doesn't match the dimension for the tree</exception>
        /// <exception cref="NeighborsOutOfRangeException">if <I>n</I> is negative or exceeds tree size </exception>
        public object[] Nearest(double[] key, int numNeighbors)
        {
            if (numNeighbors < 0 || numNeighbors > _count) throw new NeighborsOutOfRangeException();

            if (key.Length != _k) throw new KeySizeException();

            object[] neighbors = new object[numNeighbors];
            NearestNeighborList nnl = new NearestNeighborList(numNeighbors);

            // initial call is with infinite hyper-rectangle and max distance
            HRect hr = HRect.InfiniteHRect(key.Length);
            const double maxDistSqd = 1.79769e+30;
            HPoint keyp = new HPoint(key);

            KdNode.Nnbr(_root, keyp, hr, maxDistSqd, 0, _k, nnl);

            for (int i = 0; i < numNeighbors; ++i)
            {
                KdNode kd = (KdNode)nnl.RemoveHighest();
                neighbors[numNeighbors - i - 1] = kd.V;
            }

            return neighbors;
        }
Example #4
0
        /// <summary>
        /// Method Nearest Neighbor from Andrew Moore's thesis. Numbered
        /// comments are direct quotes from there. Step "SDL" is added to
        /// make the algorithm work correctly.  NearestNeighborList solution
        /// courtesy of Bjoern Heckel.
        /// </summary>
        /// <param name="kd"></param>
        /// <param name="target"></param>
        /// <param name="hr"></param>
        /// <param name="maxDistSqd"></param>
        /// <param name="lev"></param>
        /// <param name="k"></param>
        /// <param name="nnl"></param>
        public static void Nnbr(KdNode kd, HPoint target, HRect hr,
                                double maxDistSqd, int lev, int k,
                                NearestNeighborList nnl)
        {
            // 1. if kd is empty then set dist-sqd to infinity and exit.
            if (kd == null)
            {
                return;
            }

            // 2. s := split field of kd
            int s = lev % k;

            // 3. pivot := dom-elt field of kd
            HPoint pivot = kd.K;
            double pivotToTarget = HPoint.SquareDistance(pivot, target);

            // 4. Cut hr into to sub-hyperrectangles left-hr and right-hr.
            //    The cut plane is through pivot and perpendicular to the s
            //    dimension.
            HRect leftHr = hr; // optimize by not cloning
            HRect rightHr = hr.Copy();
            leftHr.Max[s] = pivot[s];
            rightHr.Min[s] = pivot[s];

            // 5. target-in-left := target_s <= pivot_s
            bool targetInLeft = target[s] < pivot[s];

            KdNode nearerKd;
            HRect nearerHr;
            KdNode furtherKd;
            HRect furtherHr;

            if (targetInLeft)
            {
                // 6. if target-in-left then
                //    6.1. nearer-kd := left field of kd and nearer-hr := left-hr
                //    6.2. further-kd := right field of kd and further-hr := right-hr
                nearerKd = kd.Left;
                nearerHr = leftHr;
                furtherKd = kd.Right;
                furtherHr = rightHr;
            }
            else
            {
                //
                // 7. if not target-in-left then
                //    7.1. nearer-kd := right field of kd and nearer-hr := right-hr
                //    7.2. further-kd := left field of kd and further-hr := left-hr
                nearerKd = kd.Right;
                nearerHr = rightHr;
                furtherKd = kd.Left;
                furtherHr = leftHr;
            }

            // 8. Recursively call Nearest Neighbor with paramters
            //    (nearer-kd, target, nearer-hr, max-dist-sqd), storing the
            //    results in nearest and dist-sqd
            Nnbr(nearerKd, target, nearerHr, maxDistSqd, lev + 1, k, nnl);

            double distSqd;

            if (!nnl.IsCapacityReached)
            {
                distSqd = 1.79769e+30; // Double.MaxValue;
            }
            else
            {
                distSqd = nnl.MaxPriority;
            }

            // 9. max-dist-sqd := minimum of max-dist-sqd and dist-sqd
            maxDistSqd = Math.Min(maxDistSqd, distSqd);

            // 10. A nearer point could only lie in further-kd if there were some
            //     part of further-hr within distance sqrt(max-dist-sqd) of
            //     target.  If this is the case then
            HPoint closest = furtherHr.Closest(target);
            if (HPoint.EuclideanDistance(closest, target) < Math.Sqrt(maxDistSqd))
            {
                // 10.1 if (pivot-target)^2 < dist-sqd then
                if (pivotToTarget < distSqd)
                {
                    // 10.1.1 nearest := (pivot, range-elt field of kd)

                    // 10.1.2 dist-sqd = (pivot-target)^2
                    distSqd = pivotToTarget;

                    // add to nnl
                    if (!kd.IsDeleted)
                    {
                        nnl.Insert(kd, distSqd);
                    }

                    // 10.1.3 max-dist-sqd = dist-sqd
                    // max_dist_sqd = dist_sqd;
                    if (nnl.IsCapacityReached)
                    {
                        maxDistSqd = nnl.MaxPriority;
                    }
                    else
                    {
                        maxDistSqd = 1.79769e+30; //Double.MaxValue;
                    }
                }

                // 10.2 Recursively call Nearest Neighbor with parameters
                //      (further-kd, target, further-hr, max-dist_sqd),
                //      storing results in temp-nearest and temp-dist-sqd
                Nnbr(furtherKd, target, furtherHr, maxDistSqd, lev + 1, k, nnl);
                double tempDistSqd = nnl.MaxPriority;

                // 10.3 If tmp-dist-sqd < dist-sqd then
                if (tempDistSqd < distSqd)
                {
                    // 10.3.1 nearest := temp_nearest and dist_sqd := temp_dist_sqd
                    distSqd = tempDistSqd;
                }
            }
            else if (pivotToTarget < maxDistSqd)
            {
                // SDL: otherwise, current point is nearest
                distSqd = pivotToTarget;
            }
        }