Ejemplo n.º 1
0
        /// <summary>
        /// Find min value under this dimension.
        /// </summary>
        private KDTreeNode <T> findMin(KDTreeNode <T> node, int searchdimension, int depth)
        {
            var currentDimension = depth % dimensions;

            if (currentDimension == searchdimension)
            {
                if (node.Left == null)
                {
                    return(node);
                }

                return(findMin(node.Left, searchdimension, depth + 1));
            }

            KDTreeNode <T> leftMin = null;

            if (node.Left != null)
            {
                leftMin = findMin(node.Left, searchdimension, depth + 1);
            }

            KDTreeNode <T> rightMin = null;

            if (node.Right != null)
            {
                rightMin = findMin(node.Right, searchdimension, depth + 1);
            }

            return(min(node, leftMin, rightMin, searchdimension));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Recursively find leaf node to insert
        /// at each level comparing against the next dimension.
        /// </summary>
        private void insert(KDTreeNode <T> currentNode, T[] point, int depth)
        {
            var currentDimension = depth % dimensions;

            if (point[currentDimension].CompareTo(currentNode.Points[currentDimension]) < 0)
            {
                if (currentNode.Left == null)
                {
                    currentNode.Left        = new KDTreeNode <T>(dimensions, currentNode);
                    currentNode.Left.Points = new T[dimensions];
                    copyPoints(currentNode.Left.Points, point);
                    return;
                }
                else
                {
                    insert(currentNode.Left, point, depth + 1);
                }
            }
            else if (point[currentDimension].CompareTo(currentNode.Points[currentDimension]) >= 0)
            {
                if (currentNode.Right == null)
                {
                    currentNode.Right        = new KDTreeNode <T>(dimensions, currentNode);
                    currentNode.Right.Points = new T[dimensions];
                    copyPoints(currentNode.Right.Points, point);
                    return;
                }
                else
                {
                    insert(currentNode.Right, point, depth + 1);
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Returns the closest node between currentBest and CurrentNode to point
        /// </summary>
        private KDTreeNode <T> getClosestToPoint(IDistanceCalculator <T> distanceCalculator,
                                                 KDTreeNode <T> currentBest, KDTreeNode <T> currentNode, T[] point)
        {
            if (distanceCalculator.Compare(currentBest.Points,
                                           currentNode.Points, point) < 0)
            {
                return(currentBest);
            }

            return(currentNode);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Is the point in node is within start and end points.
        /// </summary>
        private bool inRange(KDTreeNode <T> node, T[] start, T[] end)
        {
            for (int i = 0; i < node.Points.Length; i++)
            {
                //if not (start is less than node && end is greater than node)
                if (!(start[i].CompareTo(node.Points[i]) <= 0 &&
                      end[i].CompareTo(node.Points[i]) >= 0))
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Inserts a new item to this Kd tree.
        /// Time complexity: O(log(n))
        /// </summary>
        public void Insert(T[] point)
        {
            if (root == null)
            {
                root        = new KDTreeNode <T>(dimensions, null);
                root.Points = new T[dimensions];
                copyPoints(root.Points, point);
                Count++;
                return;
            }

            insert(root, point, 0);
            Count++;
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Handle the three cases for deletion.
        /// </summary>
        private void handleDeleteCases(KDTreeNode <T> currentNode, T[] point, int depth)
        {
            //case one node is leaf
            if (currentNode.IsLeaf)
            {
                if (currentNode == root)
                {
                    root = null;
                }
                else
                {
                    if (currentNode.IsLeftChild)
                    {
                        currentNode.Parent.Left = null;
                    }
                    else
                    {
                        currentNode.Parent.Right = null;
                    }

                    return;
                }
            }

            //case 2 right subtree is not null
            if (currentNode.Right != null)
            {
                var minNode = findMin(currentNode.Right, depth % dimensions, depth + 1);
                copyPoints(currentNode.Points, minNode.Points);

                delete(currentNode.Right, minNode.Points, depth + 1);
            }
            //case 3 left subtree is not null
            else if (currentNode.Left != null)
            {
                var minNode = findMin(currentNode.Left, depth % dimensions, depth + 1);
                copyPoints(currentNode.Points, minNode.Points);

                delete(currentNode.Left, minNode.Points, depth + 1);

                //now move to right
                currentNode.Right = currentNode.Left;
                currentNode.Left  = null;
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Recursively find points in given range.
        /// </summary>
        private List <T[]> rangeSearch(List <T[]> result,
                                       KDTreeNode <T> currentNode,
                                       T[] start, T[] end, int depth)
        {
            if (currentNode == null)
            {
                return(result);
            }

            var currentDimension = depth % dimensions;

            if (currentNode.IsLeaf)
            {
                //start is less than current node
                if (inRange(currentNode, start, end))
                {
                    result.Add(currentNode.Points);
                }
            }
            //if start is less than current
            //move left
            else
            {
                if (start[currentDimension].CompareTo(currentNode.Points[currentDimension]) < 0)
                {
                    rangeSearch(result, currentNode.Left, start, end, depth + 1);
                }
                //if start is greater than current
                //and end is greater than current
                //move right
                if (end[currentDimension].CompareTo(currentNode.Points[currentDimension]) > 0)
                {
                    rangeSearch(result, currentNode.Right, start, end, depth + 1);
                }

                //start is less than current node
                if (inRange(currentNode, start, end))
                {
                    result.Add(currentNode.Points);
                }
            }

            return(result);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Returns min of given three nodes on search dimension.
        /// </summary>
        private KDTreeNode <T> min(KDTreeNode <T> node,
                                   KDTreeNode <T> leftMin, KDTreeNode <T> rightMin,
                                   int searchdimension)
        {
            var min = node;

            if (leftMin != null && min.Points[searchdimension]
                .CompareTo(leftMin.Points[searchdimension]) > 0)
            {
                min = leftMin;
            }

            if (rightMin != null && min.Points[searchdimension]
                .CompareTo(rightMin.Points[searchdimension]) > 0)
            {
                min = rightMin;
            }

            return(min);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Delete point by locating it recursively.
        /// </summary>
        private void delete(KDTreeNode <T> currentNode, T[] point, int depth)
        {
            if (currentNode == null)
            {
                throw new Exception("Given deletion point do not exist in this kd tree.");
            }

            var currentDimension = depth % dimensions;

            if (DoMatch(currentNode.Points, point))
            {
                handleDeleteCases(currentNode, point, depth);
                return;
            }

            if (point[currentDimension].CompareTo(currentNode.Points[currentDimension]) < 0)
            {
                delete(currentNode.Left, point, depth + 1);
            }
            else if (point[currentDimension].CompareTo(currentNode.Points[currentDimension]) >= 0)
            {
                delete(currentNode.Right, point, depth + 1);
            }
        }
Ejemplo n.º 10
0
 internal KDTreeEnumerator(KDTreeNode <T> root)
 {
     this.root = root;
 }
Ejemplo n.º 11
0
 internal KDTreeNode(int dimensions, KDTreeNode <T> parent)
 {
     Points = new T[dimensions];
     Parent = parent;
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Recursively find leaf node to insert
        /// at each level comparing against the next dimension.
        /// </summary>
        private KDTreeNode <T> findNearestNeighbour(KDTreeNode <T> currentNode,
                                                    T[] searchPoint, int depth,
                                                    IDistanceCalculator <T> distanceCalculator)
        {
            var            currentDimension = depth % dimensions;
            KDTreeNode <T> currentBest      = null;

            var compareResult = searchPoint[currentDimension]
                                .CompareTo(currentNode.Points[currentDimension]);

            //move toward search point until leaf is reached
            if (compareResult < 0)
            {
                if (currentNode.Left != null)
                {
                    currentBest = findNearestNeighbour(currentNode.Left,
                                                       searchPoint, depth + 1, distanceCalculator);
                }
                else
                {
                    currentBest = currentNode;
                }

                //currentBest is greater than point to current node distance
                //or if right node sits on split plane
                //then also move left
                if (currentNode.Right != null &&
                    (distanceCalculator.Compare(currentNode.Points[currentDimension], searchPoint[currentDimension], searchPoint, currentBest.Points) < 0 ||
                     currentNode.Right.Points[currentDimension]
                     .CompareTo(currentNode.Points[currentDimension]) == 0))
                {
                    var rightBest = findNearestNeighbour(currentNode.Right,
                                                         searchPoint, depth + 1,
                                                         distanceCalculator);

                    currentBest = getClosestToPoint(distanceCalculator, currentBest, rightBest, searchPoint);
                }
                //now recurse up from leaf updating current Best
                currentBest = getClosestToPoint(distanceCalculator, currentBest, currentNode, searchPoint);
            }
            else if (compareResult >= 0)
            {
                if (currentNode.Right != null)
                {
                    currentBest = findNearestNeighbour(currentNode.Right,
                                                       searchPoint, depth + 1, distanceCalculator);
                }
                else
                {
                    currentBest = currentNode;
                }

                //currentBest is greater than point to current node distance
                //or if search point lies on split plane
                //then also move left
                if (currentNode.Left != null &&
                    (distanceCalculator.Compare(currentNode.Points[currentDimension], searchPoint[currentDimension], searchPoint, currentBest.Points) < 0 || compareResult == 0))
                {
                    var leftBest = findNearestNeighbour(currentNode.Left,
                                                        searchPoint, depth + 1,
                                                        distanceCalculator);

                    currentBest = getClosestToPoint(distanceCalculator, currentBest, leftBest, searchPoint);
                }

                //now recurse up from leaf updating current Best
                currentBest = getClosestToPoint(distanceCalculator, currentBest, currentNode, searchPoint);
            }


            return(currentBest);
        }