예제 #1
0
파일: KDTree.cs 프로젝트: AlvaIce/GFJT-2020
        /// <summary>
        /// Find KD-tree nodes whose keys are <I>n</I> farthest neighbors from
        /// key.  Neighbors are returned in descending 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[] Farthest(double[] key, int numNeighbors)
        {
            if (numNeighbors < 0 || numNeighbors > _count)
            {
                throw new NeighborsOutOfRangeException();
            }

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

            object[]             neighbors = new object[numNeighbors];
            FarthestNeighborList fnl       = new FarthestNeighborList(numNeighbors);

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

            KdNode.FarthestNeighbor(_root, keyp, hr, 0, 0, _k, fnl);
            //KDNode.nnbr(_root, keyp, hr, max_dist_sqd, 0, _k, nnl);

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

            return(neighbors);
        }
예제 #2
0
        /// <summary>
        /// A Static method for returning the square distance between two coordinates
        /// </summary>
        /// <param name="x">One coordinate</param>
        /// <param name="y">A second coordinate</param>
        /// <returns>A double representing the square distance</returns>
        public static double SquareDistance(HPoint x, HPoint y)
        {
            HPoint a = x;
            HPoint b = y;

            int    minOrdinate = Math.Min(x.NumOrdinates, y.NumOrdinates);
            double dist        = 0;

            if (a != null && b != null)
            {
                // if we can calculate using direct access to the internal coord variable,
                // it will be slightly faster.
                for (int i = 0; i < minOrdinate; ++i)
                {
                    double diff = (a[i] - b[i]);
                    dist += (diff * diff);
                }
            }
            else
            {
                // otherwise, just use the standard ICoordinate accessors
                for (int i = 0; i < minOrdinate; ++i)
                {
                    double diff = (x[i] - y[i]);
                    dist += (diff * diff);
                }
            }

            return(dist);
        }
예제 #3
0
파일: KDNode.cs 프로젝트: AlvaIce/GFJT-2020
        /// <summary>
        /// Inserts a
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="t"></param>
        /// <param name="lev"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        /// <remarks> Method ins translated from 352.ins.c of Gonnet and Baeza-Yates</remarks>
        public static KdNode Insert(HPoint key, object value, KdNode t, int lev, int k)
        {
            if (t == null)
            {
                t = new KdNode(key, value);
            }
            else if (key.Equals(t.K))
            {
                // "re-insert"
                if (t.IsDeleted)
                {
                    t.IsDeleted = false;
                    t.V         = value;
                }
                else
                {
                    throw (new KeyDuplicateException());
                }
            }
            else if (key[lev] > t.K[lev])
            {
                t.Right = Insert(key, value, t.Right, (lev + 1) % k, k);
            }
            else
            {
                t.Left = Insert(key, value, t.Left, (lev + 1) % k, k);
            }

            return(t);
        }
예제 #4
0
파일: KDNode.cs 프로젝트: AlvaIce/GFJT-2020
        /// <summary>
        /// Searches for values in a range
        /// </summary>
        /// <param name="lowk"></param>
        /// <param name="uppk"></param>
        /// <param name="t"></param>
        /// <param name="lev"></param>
        /// <param name="k"></param>
        /// <param name="v"></param>
        /// <remarks>Method rsearch translated from 352.range.c of Gonnet and Baeza-Yates</remarks>
        public static void SearchRange(HPoint lowk, HPoint uppk, KdNode t, int lev,
                                       int k, List <KdNode> v)
        {
            if (t == null)
            {
                return;
            }
            if (lowk[lev] <= t.K[lev])
            {
                SearchRange(lowk, uppk, t.Left, (lev + 1) % k, k, v);
            }
            int j;

            for (j = 0; j < k && lowk[j] <= t.K[j] &&
                 uppk[j] >= t.K[j]; j++)
            {
            }
            if (j == k)
            {
                v.Add(t);
            }
            if (uppk[lev] > t.K[lev])
            {
                SearchRange(lowk, uppk, t.Right, (lev + 1) % k, k, v);
            }
        }
예제 #5
0
        /// <summary>
        /// This method calculates the furthest point on the rectangle
        /// from the specified point.  This is to determine if it is
        /// possible for any of the members of the closer rectangle
        /// to be positioned further away from the test point than
        /// the points in the hyper-extent that is further from the point.
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public HPoint Farthest(HPoint t)
        {
            int    len = t.NumOrdinates;
            HPoint p   = new HPoint(len);

            for (int i = 0; i < len; ++i)
            {
                if (t[i] <= Min[i])
                {
                    p[i] = Max[i];
                }
                else if (t[i] >= Max[i])
                {
                    p[i] = Min[i];
                }
                else
                {
                    // Calculating the closest position always uses the point, but
                    // to calculate the furthest position, we actually want to
                    // pick the furhter of two extremes, in order to pick up the
                    // diagonal distance.
                    // p[i] = t[i];
                    if (t[i] - Min[i] > Max[i] - t[i])
                    {
                        p[i] = Min[i];
                    }
                    else
                    {
                        p[i] = Max[i];
                    }
                }
            }
            return(p);
        }
예제 #6
0
파일: KDTree.cs 프로젝트: AlvaIce/GFJT-2020
        /// <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);
        }
예제 #7
0
파일: KDNode.cs 프로젝트: AlvaIce/GFJT-2020
 /// <summary>
 /// Constructs a new instance of the KDNode.
 /// </summary>
 /// <param name="key">A Hyper Point representing the key to use for storing this value</param>
 /// <param name="value">A valid object value to use for copying this.</param>
 /// <remarks>The constructor is used only by class; other methods are static</remarks>
 private KdNode(HPoint key, object value)
 {
     K          = key;
     V          = value;
     Left       = null;
     Right      = null;
     _isDeleted = false;
 }
예제 #8
0
 /// <summary>
 /// Constructs a new instance of the KDNode.
 /// </summary>
 /// <param name="key">A Hyper Point representing the key to use for storing this value</param>
 /// <param name="value">A valid object value to use for copying this.</param>
 /// <remarks>The constructor is used only by class; other methods are static</remarks>
 private KdNode(HPoint key, object value)
 {
     K = key;
     V = value;
     Left = null;
     Right = null;
     _isDeleted = false;
 }
예제 #9
0
        /// <summary>
        /// Calculates the square of the Euclidean distance between this point and the other point.
        /// </summary>
        /// <param name="p">Any valid implementation of ICoordinate</param>
        /// <returns>A double representing the distances.</returns>
        public double SquareHyperDistance(HPoint p)
        {
            int    maxOrdinate = Math.Min(p.NumOrdinates, NumOrdinates);
            double dist        = 0;

            for (int i = 0; i < maxOrdinate; i++)
            {
                double diff = (p[i] - this[i]);
                dist += (diff * diff);
            }
            return(dist);
        }
예제 #10
0
파일: KDNode.cs 프로젝트: AlvaIce/GFJT-2020
        /// <summary>
        /// Searches for a specific value
        /// </summary>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        /// <remarks>Method srch translated from 352.srch.c of Gonnet and Baeza-Yates</remarks>
        public static KdNode Search(HPoint key, KdNode t, int k)
        {
            for (int lev = 0; t != null; lev = (lev + 1) % k)
            {
                if (!t.IsDeleted && key.Equals(t.K))
                {
                    return(t);
                }
                t = key[lev] > t.K[lev] ? t.Right : t.Left;
            }

            return(null);
        }
예제 #11
0
        /// <summary>
        /// Calculates a new HRect object that has a nearly infinite bounds.
        /// </summary>
        /// <param name="d">THe number of dimensions to use</param>
        /// <returns>A new HRect where the minimum is negative infinity, and the maximum is positive infinity</returns>
        /// <remarks>Used in initial conditions of KdTree.nearest()</remarks>
        public static HRect InfiniteHRect(int d)
        {
            HPoint vmin = new HPoint(d);
            HPoint vmax = new HPoint(d);

            for (int i = 0; i < d; ++i)
            {
                vmin[i] = Double.NegativeInfinity;
                vmax[i] = Double.PositiveInfinity;
            }

            return(new HRect(vmin, vmax));
        }
예제 #12
0
        /// <summary>
        /// If the specified HRect does not intersect this HRect, this returns null.  Otherwise,
        /// this will return a smaller rectangular region that represents the intersection
        /// of the two bounding regions.
        /// </summary>
        /// <param name="region">Another HRect object to intersect with this one.</param>
        /// <returns>The HRect that represents the intersection area for the two bounding boxes.</returns>
        /// <remarks>currently unused</remarks>
        public HRect Intersection(HRect region)
        {
            HPoint newmin = new HPoint(Min.NumOrdinates);
            HPoint newmax = new HPoint(Min.NumOrdinates);

            for (int i = 0; i < Min.NumOrdinates; ++i)
            {
                newmin[i] = Math.Max(Min[i], region.Min[i]);
                newmax[i] = Math.Min(Max[i], region.Max[i]);
                if (newmin[i] >= newmax[i])
                {
                    return(null);
                }
            }

            return(new HRect(newmin, newmax));
        }
예제 #13
0
        /// <summary>
        /// Calculates the closest point on the hyper-extent to the specified point.
        /// from Moore's eqn. 6.6
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public HPoint Closest(HPoint t)
        {
            int    len = t.NumOrdinates;
            HPoint p   = new HPoint(len);

            for (int i = 0; i < len; ++i)
            {
                if (t[i] <= Min[i])
                {
                    p[i] = Min[i];
                }
                else if (t[i] >= Max[i])
                {
                    p[i] = Max[i];
                }
                else
                {
                    p[i] = t[i];
                }
            }
            return(p);
        }
예제 #14
0
 /// <summary>
 /// Calculates the Euclidean distance between the two coordinates
 /// </summary>
 /// <param name="x">An ICoordinate</param>
 /// <param name="y">Another ICoordinate</param>
 /// <returns>A double representing the distance</returns>
 public static double EuclideanDistance(HPoint x, HPoint y)
 {
     return(Math.Sqrt(SquareDistance(x, y)));
 }
예제 #15
0
 /// <summary>
 /// Calculates the distance in comparison with any coordinate.  The coordinate with fewer dimensions
 /// will determine the dimensionality for the comparison.
 /// </summary>
 /// <param name="p"></param>
 /// <returns></returns>
 public double HyperDistance(HPoint p)
 {
     return(Math.Sqrt(SquareHyperDistance(p)));
 }
예제 #16
0
        /// <summary>
        /// Find KD-tree nodes whose keys are <I>n</I> farthest neighbors from
        /// key.  Neighbors are returned in descending 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[] Farthest(double[] key, int numNeighbors)
        {
            if (numNeighbors < 0 || numNeighbors > _count) throw new NeighborsOutOfRangeException();

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

            object[] neighbors = new object[numNeighbors];
            FarthestNeighborList fnl = new FarthestNeighborList(numNeighbors);

            // initial call is with infinite hyper-rectangle and max distance
            HRect hr = HRect.InfiniteHRect(key.Length);
            //double max_dist_sqd = 1.79769e+30; //Double.MaxValue;
            HPoint keyp = new HPoint(key);
            KdNode.FarthestNeighbor(_root, keyp, hr, 0, 0, _k, fnl);
            //KDNode.nnbr(_root, keyp, hr, max_dist_sqd, 0, _k, nnl);

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

            return neighbors;
        }
예제 #17
0
        // Internal is being used for performance for KD calculations, where these would normally be private.

        /// <summary>
        /// Constructs a new instance of a rectangle binding structure based on a specified number of dimensions
        /// </summary>
        /// <param name="numDimensions">An integer representing the number of dimensions.  For X, Y coordinates, this should be 2.</param>
        public HRect(int numDimensions)
        {
            Min = new HPoint(numDimensions);
            Max = new HPoint(numDimensions);
        }
예제 #18
0
        /// <summary>
        /// If the specified HRect does not intersect this HRect, this returns null.  Otherwise,
        /// this will return a smaller rectangular region that represents the intersection
        /// of the two bounding regions.
        /// </summary>
        /// <param name="region">Another HRect object to intersect with this one.</param>
        /// <returns>The HRect that represents the intersection area for the two bounding boxes.</returns>
        /// <remarks>currently unused</remarks>
        public HRect Intersection(HRect region)
        {
            HPoint newmin = new HPoint(Min.NumOrdinates);
            HPoint newmax = new HPoint(Min.NumOrdinates);

            for (int i = 0; i < Min.NumOrdinates; ++i)
            {
                newmin[i] = Math.Max(Min[i], region.Min[i]);
                newmax[i] = Math.Min(Max[i], region.Max[i]);
                if (newmin[i] >= newmax[i]) return null;
            }

            return new HRect(newmin, newmax);
        }
예제 #19
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;
        }
예제 #20
0
 /// <summary>
 /// Searches for values in a range
 /// </summary>
 /// <param name="lowk"></param>
 /// <param name="uppk"></param>
 /// <param name="t"></param>
 /// <param name="lev"></param>
 /// <param name="k"></param>
 /// <param name="v"></param>
 /// <remarks>Method rsearch translated from 352.range.c of Gonnet and Baeza-Yates</remarks>
 public static void SearchRange(HPoint lowk, HPoint uppk, KdNode t, int lev,
                                int k, List<KdNode> v)
 {
     if (t == null) return;
     if (lowk[lev] <= t.K[lev])
     {
         SearchRange(lowk, uppk, t.Left, (lev + 1) % k, k, v);
     }
     int j;
     for (j = 0; j < k && lowk[j] <= t.K[j] &&
                 uppk[j] >= t.K[j]; j++)
     {
     }
     if (j == k) v.Add(t);
     if (uppk[lev] > t.K[lev])
     {
         SearchRange(lowk, uppk, t.Right, (lev + 1) % k, k, v);
     }
 }
예제 #21
0
        /// <summary>
        /// This method was written by Ted Dunsford by restructuring the nearest neighbor
        /// algorithm presented by Andrew and Bjoern
        /// </summary>
        /// <param name="kd">Since this is recursive, this represents the current node</param>
        /// <param name="target">The target is the HPoint that we are trying to calculate the farthest distance from</param>
        /// <param name="hr">In this case, the hr is the hyper rectangle bounding the region that must contain the furthest point.</param>
        /// <param name="maxDistSqd">The maximum distance that we have calculated thus far, and will therefore be testing against.</param>
        /// <param name="lev">The integer based level of that we have recursed to in the tree</param>
        /// <param name="k">The dimensionality of the kd tree</param>
        /// <param name="fnl">A list to contain the output, prioritized by distance</param>
        public static void FarthestNeighbor(KdNode kd, HPoint target, HRect hr,
                                            double maxDistSqd, int lev, int k,
                                            FarthestNeighborList fnl)
        {
            // 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
            //FarthestNeighbor(nearer_kd, target, nearer_hr, max_dist_sqd, lev + 1, K, nnl);

            // This line changed by Ted Dunsford to attempt to find the farther point
            FarthestNeighbor(furtherKd, target, furtherHr, maxDistSqd, lev + 1, k, fnl);

            //KDNode nearest = (KDNode)nnl.Highest;
            double distSqd;

            if (!fnl.IsCapacityReached)
            {
                //dist_sqd = 1.79769e+30; // Double.MaxValue;
                distSqd = 0;
            }
            else
            {
                distSqd = fnl.MinimumPriority;
            }

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

            maxDistSqd = Math.Max(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 = further_hr.Closest(target);
            HPoint furthest = nearerHr.Farthest(target);
            //if (HPoint.EuclideanDistance(closest, target) < Math.Sqrt(max_dist_sqd))
            if (HPoint.EuclideanDistance(furthest, 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)
                    //nearest = kd;

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

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

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

                // 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
                FarthestNeighbor(nearerKd, target, nearerHr, maxDistSqd, lev + 1, k, fnl);

                double tempDistSqd = fnl.MinimumPriority;

                // 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;
            }
        }
예제 #22
0
 /// <summary>
 /// Creates a new bounding rectangle based on the two coordinates specified.  It is assumed that
 /// the vmin and vmax coordinates have already been correctly calculated.
 /// </summary>
 /// <param name="vmin"></param>
 /// <param name="vmax"></param>
 public HRect(HPoint vmin, HPoint vmax)
 {
     Min = vmin.Copy();
     Max = vmax.Copy();
 }
예제 #23
0
파일: KDNode.cs 프로젝트: AlvaIce/GFJT-2020
        /// <summary>
        /// This method was written by Ted Dunsford by restructuring the nearest neighbor
        /// algorithm presented by Andrew and Bjoern
        /// </summary>
        /// <param name="kd">Since this is recursive, this represents the current node</param>
        /// <param name="target">The target is the HPoint that we are trying to calculate the farthest distance from</param>
        /// <param name="hr">In this case, the hr is the hyper rectangle bounding the region that must contain the furthest point.</param>
        /// <param name="maxDistSqd">The maximum distance that we have calculated thus far, and will therefore be testing against.</param>
        /// <param name="lev">The integer based level of that we have recursed to in the tree</param>
        /// <param name="k">The dimensionality of the kd tree</param>
        /// <param name="fnl">A list to contain the output, prioritized by distance</param>
        public static void FarthestNeighbor(KdNode kd, HPoint target, HRect hr,
                                            double maxDistSqd, int lev, int k,
                                            FarthestNeighborList fnl)
        {
            // 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
            //FarthestNeighbor(nearer_kd, target, nearer_hr, max_dist_sqd, lev + 1, K, nnl);

            // This line changed by Ted Dunsford to attempt to find the farther point
            FarthestNeighbor(furtherKd, target, furtherHr, maxDistSqd, lev + 1, k, fnl);

            //KDNode nearest = (KDNode)nnl.Highest;
            double distSqd;

            if (!fnl.IsCapacityReached)
            {
                //dist_sqd = 1.79769e+30; // Double.MaxValue;
                distSqd = 0;
            }
            else
            {
                distSqd = fnl.MinimumPriority;
            }

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

            maxDistSqd = Math.Max(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 = further_hr.Closest(target);
            HPoint furthest = nearerHr.Farthest(target);

            //if (HPoint.EuclideanDistance(closest, target) < Math.Sqrt(max_dist_sqd))
            if (HPoint.EuclideanDistance(furthest, 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)
                    //nearest = kd;

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

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

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

                // 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
                FarthestNeighbor(nearerKd, target, nearerHr, maxDistSqd, lev + 1, k, fnl);

                double tempDistSqd = fnl.MinimumPriority;

                // 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;
            }
        }
예제 #24
0
        /// <summary>
        /// Inserts a
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="t"></param>
        /// <param name="lev"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        /// <remarks> Method ins translated from 352.ins.c of Gonnet and Baeza-Yates</remarks>
        public static KdNode Insert(HPoint key, object value, KdNode t, int lev, int k)
        {
            if (t == null)
            {
                t = new KdNode(key, value);
            }
            else if (key.Equals(t.K))
            {
                // "re-insert"
                if (t.IsDeleted)
                {
                    t.IsDeleted = false;
                    t.V = value;
                }
                else
                {
                    throw (new KeyDuplicateException());
                }
            }
            else if (key[lev] > t.K[lev])
            {
                t.Right = Insert(key, value, t.Right, (lev + 1) % k, k);
            }
            else
            {
                t.Left = Insert(key, value, t.Left, (lev + 1) % k, k);
            }

            return t;
        }
예제 #25
0
 /// <summary>
 /// Creates a new bounding rectangle based on the two coordinates specified.  It is assumed that
 /// the vmin and vmax coordinates have already been correctly calculated.
 /// </summary>
 /// <param name="vmin"></param>
 /// <param name="vmax"></param>
 public HRect(HPoint vmin, HPoint vmax)
 {
     Min = vmin.Copy();
     Max = vmax.Copy();
 }
예제 #26
0
        // Internal is being used for performance for KD calculations, where these would normally be private.

        /// <summary>
        /// Constructs a new instance of a rectangle binding structure based on a specified number of dimensions
        /// </summary>
        /// <param name="numDimensions">An integer representing the number of dimensions.  For X, Y coordinates, this should be 2.</param>
        public HRect(int numDimensions)
        {
            Min = new HPoint(numDimensions);
            Max = new HPoint(numDimensions);
        }
예제 #27
0
        /// <summary>
        /// This method calculates the furthest point on the rectangle
        /// from the specified point.  This is to determine if it is
        /// possible for any of the members of the closer rectangle
        /// to be positioned further away from the test point than
        /// the points in the hyper-extent that is further from the point.
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public HPoint Farthest(HPoint t)
        {
            int len = t.NumOrdinates;
            HPoint p = new HPoint(len);

            for (int i = 0; i < len; ++i)
            {
                if (t[i] <= Min[i])
                {
                    p[i] = Max[i];
                }
                else if (t[i] >= Max[i])
                {
                    p[i] = Min[i];
                }
                else
                {
                    // Calculating the closest position always uses the point, but
                    // to calculate the furthest position, we actually want to
                    // pick the furhter of two extremes, in order to pick up the
                    // diagonal distance.
                    // p[i] = t[i];
                    if (t[i] - Min[i] > Max[i] - t[i])
                    {
                        p[i] = Min[i];
                    }
                    else
                    {
                        p[i] = Max[i];
                    }
                }
            }
            return p;
        }
예제 #28
0
 /// <summary>
 /// Calculates the square of the Euclidean distance between this point and the other point.
 /// </summary>
 /// <param name="p">Any valid implementation of ICoordinate</param>
 /// <returns>A double representing the distances.</returns>
 public double SquareHyperDistance(HPoint p)
 {
     int maxOrdinate = Math.Min(p.NumOrdinates, NumOrdinates);
     double dist = 0;
     for (int i = 0; i < maxOrdinate; i++)
     {
         double diff = (p[i] - this[i]);
         dist += (diff * diff);
     }
     return dist;
 }
예제 #29
0
        /// <summary>
        /// Calculates the closest point on the hyper-extent to the specified point.
        /// from Moore's eqn. 6.6
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public HPoint Closest(HPoint t)
        {
            int len = t.NumOrdinates;
            HPoint p = new HPoint(len);

            for (int i = 0; i < len; ++i)
            {
                if (t[i] <= Min[i])
                {
                    p[i] = Min[i];
                }
                else if (t[i] >= Max[i])
                {
                    p[i] = Max[i];
                }
                else
                {
                    p[i] = t[i];
                }
            }
            return p;
        }
예제 #30
0
        /// <summary>
        /// A Static method for returning the square distance between two coordinates
        /// </summary>
        /// <param name="x">One coordinate</param>
        /// <param name="y">A second coordinate</param>
        /// <returns>A double representing the square distance</returns>
        public static double SquareDistance(HPoint x, HPoint y)
        {
            HPoint a = x;
            HPoint b = y;

            int minOrdinate = Math.Min(x.NumOrdinates, y.NumOrdinates);
            double dist = 0;

            if (a != null && b != null)
            {
                // if we can calculate using direct access to the internal coord variable,
                // it will be slightly faster.
                for (int i = 0; i < minOrdinate; ++i)
                {
                    double diff = (a[i] - b[i]);
                    dist += (diff * diff);
                }
            }
            else
            {
                // otherwise, just use the standard ICoordinate accessors
                for (int i = 0; i < minOrdinate; ++i)
                {
                    double diff = (x[i] - y[i]);
                    dist += (diff * diff);
                }
            }

            return dist;
        }
예제 #31
0
 /// <summary>
 /// Calculates the Euclidean distance between the two coordinates
 /// </summary>
 /// <param name="x">An ICoordinate</param>
 /// <param name="y">Another ICoordinate</param>
 /// <returns>A double representing the distance</returns>
 public static double EuclideanDistance(HPoint x, HPoint y)
 {
     return Math.Sqrt(SquareDistance(x, y));
 }
예제 #32
0
        /// <summary>
        /// Calculates a new HRect object that has a nearly infinite bounds.
        /// </summary>
        /// <param name="d">THe number of dimensions to use</param>
        /// <returns>A new HRect where the minimum is negative infinity, and the maximum is positive infinity</returns>
        /// <remarks>Used in initial conditions of KdTree.nearest()</remarks>
        public static HRect InfiniteHRect(int d)
        {
            HPoint vmin = new HPoint(d);
            HPoint vmax = new HPoint(d);

            for (int i = 0; i < d; ++i)
            {
                vmin[i] = Double.NegativeInfinity;
                vmax[i] = Double.PositiveInfinity;
            }

            return new HRect(vmin, vmax);
        }
예제 #33
0
 /// <summary>
 /// Calculates the distance in comparison with any coordinate.  The coordinate with fewer dimensions
 /// will determine the dimensionality for the comparison.
 /// </summary>
 /// <param name="p"></param>
 /// <returns></returns>
 public double HyperDistance(HPoint p)
 {
     return Math.Sqrt(SquareHyperDistance(p));
 }
예제 #34
0
        /// <summary>
        /// Searches for a specific value
        /// </summary>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        /// <remarks>Method srch translated from 352.srch.c of Gonnet and Baeza-Yates</remarks>
        public static KdNode Search(HPoint key, KdNode t, int k)
        {
            for (int lev = 0; t != null; lev = (lev + 1) % k)
            {
                if (!t.IsDeleted && key.Equals(t.K))
                {
                    return t;
                }
                t = key[lev] > t.K[lev] ? t.Right : t.Left;
            }

            return null;
        }