Exemple #1
0
        /// <summary>
        /// Insert a new data item at a given key.
        /// </summary>
        /// <param name="key">The value which represents our data (i.e. a distance).</param>
        /// <param name="value">The data we want to store.</param>
        public void Insert(double key, KDRectangle value)
        {
            // If more room is needed, double the array size.
            if (Size >= Capacity)
            {
                // Double the capacity.
                Capacity *= 2;

                // Expand the data array.
                var newData = new KDRectangle[Capacity];
                Array.Copy(tData, newData, tData.Length);
                tData = newData;

                // Expand the key array.
                var newKeys = new double[Capacity];
                Array.Copy(tKeys, newKeys, tKeys.Length);
                tKeys = newKeys;
            }

            // Insert the new value at the end.
            Size++;
            tData[Size - 1] = value;
            tKeys[Size - 1] = key;

            // Ensure it is in the right place.
            SiftInsertedValueUp();
        }
Exemple #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 Node();
            pLeft  = new Node();

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

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

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

            // Wipe the data from this KDNode.
            tPoints = null;
            tData   = null;
        }
Exemple #3
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, KDRectangle kValue)
        {
            // Find the correct leaf node.
            Node 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.iSplitDimension] > pCursor.fSplitValue)
                {
                    pCursor = pCursor.pRight;
                }
                else
                {
                    pCursor = pCursor.pLeft;
                }
            }

            // Insert it into the leaf.
            pCursor.AddLeafPoint(tPoint, kValue);
        }
Exemple #4
0
        /// <summary>
        /// Internal helper method which swaps two values in the arrays.
        /// This swaps both data and key entries.
        /// </summary>
        /// <param name="x">The first index.</param>
        /// <param name="y">The second index.</param>
        /// <returns>The second index.</returns>
        private int Swap(int x, int y)
        {
            // Store temp.
            KDRectangle yData = tData[y];
            double      yDist = tKeys[y];

            // Swap
            tData[y] = tData[x];
            tKeys[y] = tKeys[x];
            tData[x] = yData;
            tKeys[x] = yDist;

            // Return.
            return(y);
        }
Exemple #5
0
        /// <summary>
        /// Swap out the item with the largest key in the queue.
        /// </summary>
        /// <param name="key">The new key for the largest item.</param>
        /// <param name="value">The new data for the largest item.</param>
        public void ReplaceMax(double key, KDRectangle value)
        {
            if (Size == 0)
            {
                throw new Exception();
            }
            else if (Size == 1)
            {
                ReplaceMin(key, value);
                return;
            }

            tData[1] = value;
            tKeys[1] = key;
            // Swap with pair if necessary
            if (key < tKeys[0])
            {
                Swap(0, 1);
            }
            SiftDownMax(1);
        }
Exemple #6
0
        /// <summary>
        /// Replace the item with the smallest key in the queue.
        /// </summary>
        /// <param name="key">The new minimum key.</param>
        /// <param name="value">The new minumum data value.</param>
        public void ReplaceMin(double key, KDRectangle value)
        {
            // Check for errors.
            if (Size == 0)
            {
                throw new Exception();
            }

            // Add the data.
            tData[0] = value;
            tKeys[0] = key;

            // If we have more than one item.
            if (Size > 1)
            {
                // Swap with pair if necessary.
                if (tKeys[1] < key)
                {
                    Swap(0, 1);
                }
                SiftDownMin(0);
            }
        }
Exemple #7
0
        /// <summary>
        /// Insert the point into the leaf.
        /// </summary>
        /// <param name="tPoint">The point to insert the data at.</param>
        /// <param name="kValue">The value at the point.</param>
        private void AddLeafPoint(double[] tPoint, KDRectangle kValue)
        {
            // Add the data point to this node.
            tPoints[Size] = tPoint;
            tData[Size]   = kValue;
            ExtendBounds(tPoint);
            Size++;

            // Split if the node is getting too large in terms of data.
            if (Size == tPoints.Length - 1)
            {
                // If the node is getting too physically large.
                if (CalculateSplit())
                {
                    // If the node successfully had it's split value calculated, split node.
                    SplitLeafNode();
                }
                else
                {
                    // If the node could not be split, enlarge node data capacity.
                    IncreaseLeafCapacity();
                }
            }
        }
Exemple #8
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(KDRectangle);
                return(false);
            }

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

                // Descend the tree, recording paths not taken
                while (!pCursor.IsLeaf)
                {
                    Node pNotTaken;

                    // If the seach point is larger, select the right path.
                    if (tSearchPoint[pCursor.iSplitDimension] > 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 = this.DistanceToRectangle(tSearchPoint, pNotTaken.tMinBound, pNotTaken.tMaxBound);

                    // If it is greater than the threshold, skip.
                    if (-1 >= 0 && fDistance > -1)
                    {
                        //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.bSinglePoint)
                {
                    // Work out the distance between this point and the search point.
                    double fDistance = this.Distance(pCursor.tPoints[0], tSearchPoint);

                    // Skip if the point exceeds the threshold.
                    // Technically this should never happen, but be prescise.
                    if (-1 >= 0 && fDistance >= -1)
                    {
                        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.tData[i]);
                            }

                            // Otherwise insert.
                            else
                            {
                                pEvaluated.Insert(fDistance, pCursor.tData[i]);
                            }
                        }
                    }
                }

                // If the points in the KD node are spread out.
                else
                {
                    // Treat the distance of each point seperately.
                    for (int i = 0; i < pCursor.Size; ++i)
                    {
                        // Compute the distance between the points.
                        double fDistance = this.Distance(pCursor.tPoints[i], tSearchPoint);

                        // Skip if it exceeds the threshold.
                        if (-1 >= 0 && fDistance >= -1)
                        {
                            continue;
                        }

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

                        // Otherwise replace the max.
                        else if (fDistance < pEvaluated.MaxKey)
                        {
                            pEvaluated.ReplaceMax(fDistance, pCursor.tData[i]);
                        }
                    }
                }
            }

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

            iPointsRemaining--;
            _CurrentDistance = pEvaluated.MinKey;
            _Current         = pEvaluated.Min;
            pEvaluated.RemoveMin();
            return(true);
        }