コード例 #1
0
        /// <summary>
        /// Insert a new point into this leaf node.
        /// </summary>
        /// <param name="tPoint">The position which represents the data.</param>
        /// <param name="kValue">The value of the data.</param>
        public void AddPoint(double[] tPoint, T kValue)
        {
            // Find the correct leaf node.
            KDNode_Rednaxela <T> pCursor = this;

            while (!pCursor.IsLeaf)
            {
                // Extend the size of the leaf.
                pCursor.ExtendBounds(tPoint);
                pCursor.Size++;

                // If it is larger select the right, or lower,  select the left.
                if (tPoint[pCursor.splitDimension] > pCursor.fSplitValue)
                {
                    pCursor = pCursor.pRight;
                }
                else
                {
                    pCursor = pCursor.pLeft;
                }
            }

            // Insert it into the leaf.
            pCursor.AddLeafPoint(tPoint, kValue);
        }
コード例 #2
0
        /// <summary>
        /// Split this leaf node by creating left and right children, then moving all the children of
        /// this node into the respective buckets.
        /// </summary>
        private void SplitLeafNode()
        {
            // Create the new children.
            pRight = new KDNode_Rednaxela <T>(dimensions, bucketCapacity);
            pLeft  = new KDNode_Rednaxela <T>(dimensions, bucketCapacity);

            // Move each item in this leaf into the children.
            for (int i = 0; i < Size; ++i)
            {
                // Store.
                double[] tOldPoint = points[i];
                T        kOldData  = data[i];

                // If larger, put it in the right.
                if (tOldPoint[splitDimension] > fSplitValue)
                {
                    pRight.AddLeafPoint(tOldPoint, kOldData);
                }

                // If smaller, put it in the left.
                else
                {
                    pLeft.AddLeafPoint(tOldPoint, kOldData);
                }
            }

            // Wipe the data from this KDNode.
            points = null;
            data   = null;
        }
コード例 #3
0
        private void CheckSinglePoint(KDNode_Rednaxela <T> pCursor)
        {
            // Work out the distance between this point and the search point.
            double fDistance = kDistanceFunction.Distance(pCursor.points[0], tSearchPoint);

            //// Skip if the point exceeds the threshold.
            //// Technically this should never happen, but be prescise.
            //if (fThreshold >= 0 && fDistance >= fThreshold)
            //    continue;

            // Add the point if either need more points or it's closer than furthest on list so far.
            if (pEvaluated.Size < iPointsRemaining || fDistance <= pEvaluated.MaxKey)
            {
                for (int i = 0; i < pCursor.Size; ++i)
                {
                    // If we don't need any more, replace max
                    if (pEvaluated.Size == iPointsRemaining)
                    {
                        pEvaluated.ReplaceMax(fDistance, pCursor.data[i], i);
                    }

                    // Otherwise insert.
                    else
                    {
                        pEvaluated.Insert(fDistance, pCursor.data[i], i);
                    }
                }
            }
        }
コード例 #4
0
        /// <summary>
        /// Construct a new nearest neighbour iterator.
        /// </summary>
        /// <param name="pRoot">The root of the tree to begin searching from.</param>
        /// <param name="tSearchPoint">The point in n-dimensional space to search.</param>
        /// <param name="kDistance">The distance function used to evaluate the points.</param>
        /// <param name="iMaxPoints">The max number of points which can be returned by this iterator.  Capped to max in tree.</param>
        /// <param name="fThreshold">Threshold to apply to the search space.  Negative numbers indicate that no threshold is applied.</param>
        public NearestNeighbour(KDNode_Rednaxela <T> pRoot, double[] tSearchPoint, IDistanceFunction kDistance, int iMaxPoints, double fThreshold)
        {
            // Check the dimensionality of the search point.
            if (tSearchPoint.Length != pRoot.dimensions)
            {
                throw new Exception("Dimensionality of search point and kd-tree are not the same.");
            }

            // Store the search point.
            this.tSearchPoint = new double[tSearchPoint.Length];
            Array.Copy(tSearchPoint, this.tSearchPoint, tSearchPoint.Length);

            // Store the point count, distance function and tree root.
            this.iPointsRemaining   = Math.Min(iMaxPoints, pRoot.Size);
            this.fThreshold         = fThreshold;
            this.kDistanceFunction  = kDistance;
            this.pRoot              = pRoot;
            this.iMaxPointsReturned = iMaxPoints;
            _CurrentDistance        = -1;

            // Create an interval heap for the points we check.
            this.pEvaluated = new IntervalHeap <T>();

            // Create a min heap for the things we need to check.
            this.pPending = new MinHeap <KDNode_Rednaxela <T> >();
            this.pPending.Insert(0, pRoot);
        }
コード例 #5
0
        private void DescendPath(KDNode_Rednaxela <T> pCursor)
        {
            KDNode_Rednaxela <T> pNotTaken;

            // If the seach point is larger, select the right path.
            if (tSearchPoint[pCursor.splitDimension] > pCursor.fSplitValue)
            {
                pNotTaken = pCursor.pLeft;
                pCursor   = pCursor.pRight;
            }
            else
            {
                pNotTaken = pCursor.pRight;
                pCursor   = pCursor.pLeft;
            }

            // Calculate the shortest distance between the search point and the min and max bounds of the kd-node.
            double fDistance = kDistanceFunction.DistanceToRectangle(tSearchPoint, pNotTaken.minBound, pNotTaken.maxBound);

            //// If it is greater than the threshold, skip.
            //if (fThreshold >= 0 && fDistance > fThreshold)
            //{
            //    //pPending.Insert(fDistance, pNotTaken);
            //    continue;
            //}

            // Only add the path we need more points or the node is closer than furthest point on list so far.
            if (pEvaluated.Size < iPointsRemaining || fDistance <= pEvaluated.MaxKey)
            {
                pPending.Insert(fDistance, pNotTaken);
            }
        }
コード例 #6
0
        private void CheckSpreadOutPoints(KDNode_Rednaxela <T> pCursor)
        {
            // Treat the distance of each point seperately.
            for (int i = 0; i < pCursor.Size; ++i)
            {
                // Compute the distance between the points.
                double fDistance = kDistanceFunction.Distance(pCursor.points[i], tSearchPoint);

                //// Skip if it exceeds the threshold.
                //if (fThreshold >= 0 && fDistance >= fThreshold)
                //    continue;

                // Insert the point if we have more to take.
                if (pEvaluated.Size < iPointsRemaining)
                {
                    pEvaluated.Insert(fDistance, pCursor.data[i], i);
                }

                // Otherwise replace the max.
                else if (fDistance < pEvaluated.MaxKey)
                {
                    pEvaluated.ReplaceMax(fDistance, pCursor.data[i], i);
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Check for the next iterator item.
        /// </summary>
        /// <returns>True if we have one, false if not.</returns>
        public bool MoveNext()
        {
            // Bail if we are finished.
            if (iPointsRemaining == 0)
            {
                _Current = default(T);
                return(false);
            }

            // While we still have paths to evaluate.
            while (pPending.Size > 0 && (pEvaluated.Size == 0 || (pPending.MinKey < pEvaluated.DistanceMin)))
            {
                // If there are pending paths possibly closer than the nearest evaluated point, check it out
                KDNode_Rednaxela <T> pCursor = pPending.Min;
                pPending.RemoveMin();

                // Descend the tree, record paths not taken
                while (!pCursor.IsLeaf)
                {
                    // DescendPath(pCursor);
                    KDNode_Rednaxela <T> pNotTaken;

                    // If the seach point is larger, select the right path.
                    if (tSearchPoint[pCursor.splitDimension] > pCursor.fSplitValue)
                    {
                        pNotTaken = pCursor.pLeft;
                        pCursor   = pCursor.pRight;
                    }
                    else
                    {
                        pNotTaken = pCursor.pRight;
                        pCursor   = pCursor.pLeft;
                    }

                    // Calculate the shortest distance between the search point and the min and max bounds of the kd-node.
                    double fDistance = kDistanceFunction.DistanceToRectangle(tSearchPoint, pNotTaken.minBound, pNotTaken.maxBound);

                    //// If it is greater than the threshold, skip.
                    //if (fThreshold >= 0 && fDistance > fThreshold)
                    //{
                    //    //pPending.Insert(fDistance, pNotTaken);
                    //    continue;
                    //}

                    // Only add the path we need more points or the node is closer than furthest point on list so far.
                    if (pEvaluated.Size < iPointsRemaining || fDistance <= pEvaluated.MaxKey)
                    {
                        pPending.Insert(fDistance, pNotTaken);
                    }
                }

                // If all the points in this KD node are in one place.
                if (pCursor.IsSinglePoint)
                {
                    CheckSinglePoint(pCursor);
                }

                // If the points in the KD node are spread out.
                else
                {
                    CheckSpreadOutPoints(pCursor);
                }
            }

            // Select the point with the smallest distance.
            if (pEvaluated.Size == 0)
            {
                return(false);
            }

            iPointsRemaining--;
            _CurrentDistance = pEvaluated.DistanceMin;
            _Current         = pEvaluated.ClosestPoint;
            _CurrentIndex    = pEvaluated.ClosestPointIndex;
            pEvaluated.RemoveMin();
            return(true);
        }