public bool TryFindNodeAt(TKey[] point, out KdTreeNode <TKey, TValue> value)
        {
            var navParent = root;
            int dimension = -1;

            do
            {
                dimension = (dimension + 1) % dimensions;
                if (navParent == null)
                {
                    value = default(KdTreeNode <TKey, TValue>);
                    return(false);
                }
                else if (isNode(dimension))
                {
                    var parent = (KdTreeNode <TKey, TValue>)navParent;
                    if (typeMath.AreEqual(point, parent.Points))
                    {
                        value = parent;
                        return(true);
                    }
                }

                // Keep searching
                int compare = typeMath.Compare(point[dimension], navParent.Point);
                navParent = navParent[compare];
            }while (true);
        }
Beispiel #2
0
        private KdTreeNode <TValue> Add(TValue value, KdTreeNode <TValue> node, int depth)
        {
            if (node == null)
            {
                node = new KdTreeNode <TValue>(value);
            }
            else
            {
                // Check if node should be added to left or right sub-tree of current node.
                var dimension  = depth % this.dimensionality;
                var comparison = fieldComparer.Compare(this.locationGetter(value)[dimension],
                                                       this.locationGetter(node.Value)[dimension]);

                if (comparison <= 0)
                {
                    node.LeftChild = Add(value, node.LeftChild, depth + 1);
                }
                else
                {
                    node.RightChild = Add(value, node.RightChild, depth + 1);
                }
            }

            return(node);
        }
Beispiel #3
0
        private static KdTreeNode <TValue> Construct(KdTree <TValue, TField> tree, TValue[] elements, int startIndex,
                                                     int endIndex, int depth, ValueLocationComparer valueLocationComparer)
        {
            var length = endIndex - startIndex + 1;

            if (length == 0)
            {
                return(null);
            }

            // Sort array of elements by component of chosen dimension, in ascending magnitude.
            valueLocationComparer.Dimension = depth % tree.dimensionality;
            Array.Sort(elements, startIndex, length, valueLocationComparer);

            // Select median element as pivot.
            var medianIndex   = startIndex + length / 2;
            var medianElement = elements[medianIndex];

            // Create node and construct sub-trees around pivot element.
            var node = new KdTreeNode <TValue>(medianElement);

            node.LeftChild  = Construct(tree, elements, startIndex, medianIndex - 1, depth + 1, valueLocationComparer);
            node.RightChild = Construct(tree, elements, medianIndex + 1, endIndex, depth + 1, valueLocationComparer);

            return(node);
        }
Beispiel #4
0
 internal KdTreeNode <TKey, TValue> this[int compare]
 {
     get
     {
         if (compare <= 0)
         {
             return(LeftChild);
         }
         else
         {
             return(RightChild);
         }
     }
     set
     {
         if (compare <= 0)
         {
             LeftChild = value;
         }
         else
         {
             RightChild = value;
         }
     }
 }
Beispiel #5
0
        public bool Add(TKey[] point, TValue value)
        {
            var nodeToAdd = new KdTreeNode <TKey, TValue>(point, value);

            if (root == null)
            {
                root = new KdTreeNode <TKey, TValue>(point, value);
            }
            else
            {
                int dimension = -1;
                KdTreeNode <TKey, TValue> parent = root;

                do
                {
                    // Increment the dimension we're searching in
                    dimension = (dimension + 1) % dimensions;

                    // Does the node we're adding have the same hyperpoint as this node?
                    if (typeMath.AreEqual(point, parent.Point))
                    {
                        switch (AddDuplicateBehavior)
                        {
                        case AddDuplicateBehavior.Skip:
                            return(false);

                        case AddDuplicateBehavior.Error:
                            throw new DuplicateNodeError();

                        case AddDuplicateBehavior.Update:
                            parent.Value = value;
                            break;

                        default:
                            // Should never happen
                            throw new Exception("Unexpected AddDuplicateBehavior");
                        }
                    }

                    // Which side does this node sit under in relation to it's parent at this level?
                    int compare = typeMath.Compare(point[dimension], parent.Point[dimension]);

                    if (parent[compare] == null)
                    {
                        parent[compare] = nodeToAdd;
                        break;
                    }
                    else
                    {
                        parent = parent[compare];
                    }
                }while (true);
            }

            Count++;
            return(true);
        }
Beispiel #6
0
        private void FindNearestNNeighbors(Vector <TField> location, KdTreeNode <TValue> node,
                                           ref TValue maxBestValue, ref TField maxBestDistance, int numNeighbors, C5.IPriorityQueue <TValue> valuesList,
                                           int depth)
        {
            if (node == null)
            {
                return;
            }

            var dimension    = depth % this.dimensionality;
            var nodeLocation = this.locationGetter(node.Value);
            var distance     = (nodeLocation - location).Norm(this.dimensionality);

            // Check if current node is better than maximum best node, and replace maximum node in list with it.
            // Current node cannot be same as search location.
            if (!fieldArithmetic.AlmostEqual(distance, fieldArithmetic.Zero) &&
                fieldComparer.Compare(distance, maxBestDistance) < 0)
            {
                TValue maxValue;
                if (valuesList.Count == numNeighbors)
                {
                    maxValue = valuesList.DeleteMax();
                }
                valuesList.Add(node.Value);

                if (valuesList.Count == numNeighbors)
                {
                    maxBestValue    = valuesList.FindMax();
                    maxBestDistance = (this.locationGetter(maxBestValue) - location).Norm(this.dimensionality);
                }
            }

            // Check for best node in sub-tree of near child.
            var nearChildNode = fieldComparer.Compare(location[dimension], nodeLocation[dimension]) < 0 ?
                                node.LeftChild : node.RightChild;

            if (nearChildNode != null)
            {
                FindNearestNNeighbors(location, nearChildNode, ref maxBestValue, ref maxBestDistance, numNeighbors,
                                      valuesList, depth + 1);
            }

            // Check whether splitting hyperplane given by current node intersects with hypersphere of current smallest
            // distance around given location.
            if (fieldComparer.Compare(maxBestDistance, fieldArithmetic.Abs(fieldArithmetic.Subtract(
                                                                               nodeLocation[dimension], location[dimension]))) > 0)
            {
                // Check for best node in sub-tree of far child.
                var farChildValue = nearChildNode == node.LeftChild ? node.RightChild : node.LeftChild;

                if (farChildValue != null)
                {
                    FindNearestNNeighbors(location, farChildValue, ref maxBestValue, ref maxBestDistance, numNeighbors,
                                          valuesList, depth + 1);
                }
            }
        }
Beispiel #7
0
        private TValue FindNearestNeighbor(Vector <TField> location,
                                           KdTreeNode <TValue> node, TValue bestValue, TField bestDistance, int depth)
        {
            if (node == null)
            {
                return(bestValue);
            }

            var dimension    = depth % this.dimensionality;
            var nodeLocation = this.locationGetter(node.Value);
            var distance     = (nodeLocation - location).Norm(this.dimensionality);

            // Check if current node is better than best node.
            // Current node cannot be same as search location.
            if (!fieldArithmetic.AlmostEqual(distance, fieldArithmetic.Zero) &&
                fieldComparer.Compare(distance, bestDistance) < 0)
            {
                bestValue    = node.Value;
                bestDistance = distance;
            }

            // Check for best node in sub-tree of near child.
            var nearChildNode = fieldComparer.Compare(location[dimension], nodeLocation[dimension]) < 0 ?
                                node.LeftChild : node.RightChild;

            if (nearChildNode != null)
            {
                var nearBestValue    = FindNearestNeighbor(location, nearChildNode, bestValue, bestDistance, depth + 1);
                var nearBestLocation = this.locationGetter(nearBestValue);
                var nearBestDistance = (nearBestLocation - location).Norm(this.dimensionality);
                bestValue    = nearBestValue;
                bestDistance = nearBestDistance;
            }

            // Check whether splitting hyperplane given by current node intersects with hypersphere of current smallest
            // distance around given location.
            if (fieldComparer.Compare(bestDistance, fieldArithmetic.Abs(fieldArithmetic.Subtract(
                                                                            nodeLocation[dimension], location[dimension]))) > 0)
            {
                // Check for best node in sub-tree of far child.
                var farChildValue = nearChildNode == node.LeftChild ? node.RightChild : node.LeftChild;

                if (farChildValue != null)
                {
                    var farBestValue    = FindNearestNeighbor(location, farChildValue, bestValue, bestDistance, depth + 1);
                    var farBestLocation = this.locationGetter(farBestValue);
                    var farBestDistance = (farBestLocation - location).Norm(this.dimensionality);
                    bestValue    = farBestValue;
                    bestDistance = farBestDistance;
                }
            }

            return(bestValue);
        }
Beispiel #8
0
 private void RemoveChildNodes(KdTreeNode <TKey, TValue> node)
 {
     for (var side = -1; side <= 1; side += 2)
     {
         if (node[side] != null)
         {
             RemoveChildNodes(node[side]);
             node[side] = null;
         }
     }
 }
        public KdTreeNode <TKey, TValue> Remove(KdTreeNode <TKey, TValue> removedNode)//may be not working correct
        {
            // Is tree empty?
            if (root == null)
            {
                return(null);
            }

            KdTreeNavNode <TKey> navNode    = root;
            KdTreeNavNode <TKey> parentNode = root;
            var node = ConvertNavNode(root);

            if (typeMath.AreEqual(removedNode.Points, node.Points))
            {
                root = null;
                Count--;
                ReaddChildNodes(navNode);
                return(node);
            }

            int dimension = -1;
            int compare   = 0;

            do
            {
                dimension = (dimension + 1) % dimensions;

                if (isNode(dimension))
                {
                    node = ConvertNavNode(navNode);//todo: may be optimized without using cast
                    if (typeMath.AreEqual(removedNode.Points, node.Points) &&
                        removedNode.Value.Equals(node.Value))
                    {
                        var nodeToRemove = node;
                        parentNode[compare] = null;
                        Count--;

                        ReaddChildNodes(nodeToRemove);
                        return(nodeToRemove);
                    }
                }
                compare = typeMath.Compare(removedNode.Points[dimension], navNode.Point);

                if (navNode[compare] == null)
                {
                    // Can't find node
                    return(null);
                }
                parentNode = navNode;
                navNode    = navNode[compare];
            }while (navNode != null);
            return(null);
        }
Beispiel #10
0
        private KdTreeNode <TValue> Find(TValue value, KdTreeNode <TValue> node)
        {
            if (node == null)
            {
                return(null);
            }
            if (node.Value.Equals(value))
            {
                return(node);
            }

            return(Find(value, node.LeftChild) ?? Find(value, node.RightChild));
        }
Beispiel #11
0
        private void ReaddChildNodes(KdTreeNode <TKey, TValue> removedNode)
        {
            if (removedNode.IsLeaf)
            {
                return;
            }

            // The folllowing code might seem a little redundant but we're using
            // 2 queues so we can add the child nodes back in, in (more or less)
            // the same order they were added in the first place
            var nodesToReadd = new Queue <KdTreeNode <TKey, TValue> >();

            var nodesToReaddQueue = new Queue <KdTreeNode <TKey, TValue> >();

            if (removedNode.LeftChild != null)
            {
                nodesToReaddQueue.Enqueue(removedNode.LeftChild);
            }

            if (removedNode.RightChild != null)
            {
                nodesToReaddQueue.Enqueue(removedNode.RightChild);
            }

            while (nodesToReaddQueue.Count > 0)
            {
                var nodeToReadd = nodesToReaddQueue.Dequeue();

                nodesToReadd.Enqueue(nodeToReadd);

                for (int side = -1; side <= 1; side += 2)
                {
                    if (nodeToReadd[side] != null)
                    {
                        nodesToReaddQueue.Enqueue(nodeToReadd[side]);

                        nodeToReadd[side] = null;
                    }
                }
            }

            while (nodesToReadd.Count > 0)
            {
                var nodeToReadd = nodesToReadd.Dequeue();

                Count--;
                Add(nodeToReadd.Point, nodeToReadd.Value);
            }
        }
Beispiel #12
0
        public void RemoveAt(TKey[] point)
        {
            // Is tree empty?
            if (root == null)
            {
                return;
            }

            KdTreeNode <TKey, TValue> node;

            if (typeMath.AreEqual(point, root.Point))
            {
                node = root;
                root = null;
                Count--;
                ReaddChildNodes(node);
                return;
            }

            node = root;

            int dimension = -1;

            do
            {
                dimension = (dimension + 1) % dimensions;

                int compare = typeMath.Compare(point[dimension], node.Point[dimension]);

                if (node[compare] == null)
                {
                    // Can't find node
                    return;
                }

                if (typeMath.AreEqual(point, node[compare].Point))
                {
                    var nodeToRemove = node[compare];
                    node[compare] = null;
                    Count--;

                    ReaddChildNodes(nodeToRemove);
                }
                else
                {
                    node = node[compare];
                }
            }while (node != null);
        }
Beispiel #13
0
        /// <summary>
        /// Initializes a new instance of the <see cref="KdTree{TValue, TField}"/> class with the specified root node.
        /// </summary>
        /// <param name="dimensionality">The dimensionality of the kd-space.</param>
        /// <param name="root">The root node of the tree.</param>
        /// <param name="locationGetter">A function that returns the location of a given element in kd-space.</param>
        public KdTree(int dimensionality, KdTreeNode <TValue> root, Func <TValue, Vector <TField> > locationGetter = null)
            : this()
        {
            if (root != null)
            {
                throw new ArgumentNullException("root");
            }

            this.dimensionality = dimensionality;
            this.root           = root;
            if (locationGetter != null)
            {
                this.locationGetter = locationGetter;
            }
        }
Beispiel #14
0
        private void AddNodesToList(KdTreeNode <TKey, TValue> node, List <KdTreeNode <TKey, TValue> > nodes)
        {
            if (node == null)
            {
                return;
            }

            nodes.Add(node);

            for (var side = -1; side <= 1; side += 2)
            {
                if (node[side] != null)
                {
                    AddNodesToList(node[side], nodes);
                    node[side] = null;
                }
            }
        }
Beispiel #15
0
        private void FindInRange(Vector <TField> location,
                                 KdTreeNode <TValue> node, TField range, IList <TValue> valuesList, int depth)
        {
            if (node == null)
            {
                return;
            }

            var dimension    = depth % this.dimensionality;
            var nodeLocation = this.locationGetter(node.Value);
            var distance     = (nodeLocation - location).Norm(this.dimensionality);

            // Add current node to list if it lies within given range.
            // Current node cannot be same as search location.
            if (!fieldArithmetic.AlmostEqual(distance, fieldArithmetic.Zero) &&
                fieldComparer.Compare(distance, range) < 0)
            {
                valuesList.Add(node.Value);
            }

            // Check for nodes in sub-tree of near child.
            var nearChildNode = fieldComparer.Compare(location[dimension], nodeLocation[dimension]) < 0 ?
                                node.LeftChild : node.RightChild;

            if (nearChildNode != null)
            {
                FindInRange(location, nearChildNode, range, valuesList, depth + 1);
            }

            // Check whether splitting hyperplane given by current node intersects with hypersphere of current smallest
            // distance around given location.
            if (fieldComparer.Compare(range, fieldArithmetic.Abs(fieldArithmetic.Subtract(
                                                                     nodeLocation[dimension], location[dimension]))) > 0)
            {
                // Check for nodes in sub-tree of far child.
                var farChildNode = nearChildNode == node.LeftChild ? node.RightChild : node.LeftChild;

                if (farChildNode != null)
                {
                    FindInRange(location, farChildNode, range, valuesList, depth + 1);
                }
            }
        }
        public bool TryFindNode(TValue value, out KdTreeNode <TKey, TValue> point)
        {
            if (root == null)
            {
                point = null;
                return(false);
            }

            // First-in, First-out list of nodes to search
            var nodesToSearch = new Queue <KdTreeNavNode <TKey> >();

            nodesToSearch.Enqueue(root);

            while (nodesToSearch.Count > 0)
            {
                var nodeToSearch = nodesToSearch.Dequeue();
                if (isNode(nodeToSearch))
                {
                    var node = (KdTreeNode <TKey, TValue>)nodeToSearch;
                    if (node.Value.Equals(value))
                    {
                        point = node;
                        return(true);
                    }
                }
                else
                {
                    for (int side = -1; side <= 1; side += 2)
                    {
                        var childNode = nodeToSearch[side];

                        if (childNode != null)
                        {
                            nodesToSearch.Enqueue(childNode);
                        }
                    }
                }
            }

            point = null;
            return(false);
        }
Beispiel #17
0
        private KdTreeNode <TValue> Remove(TValue value, KdTreeNode <TValue> node, int depth)
        {
            if (node == null)
            {
                return(null);
            }

            var dimension     = depth % this.dimensionality;
            var valueLocation = this.locationGetter(value);
            var nodeLocation  = this.locationGetter(node.Value);
            var comparison    = fieldComparer.Compare(valueLocation[dimension], nodeLocation[dimension]);

            // Check if node to remove is in left sub-tree, right sub-tree, or has been found.
            if (comparison < 0)
            {
                node.LeftChild = Remove(value, node.LeftChild, depth + 1);
            }
            else if (comparison > 0)
            {
                node.RightChild = Remove(value, node.RightChild, depth + 1);
            }
            else
            {
                if (node.RightChild != null)
                {
                    node.Value      = FindMinimum(node.RightChild, dimension, depth + 1);
                    node.RightChild = Remove(node.Value, node.RightChild, depth + 1);
                }
                else if (node.LeftChild != null)
                {
                    node.Value      = FindMinimum(node.LeftChild, dimension, depth + 1);
                    node.RightChild = Remove(node.Value, node.LeftChild, depth + 1);
                    node.LeftChild  = null;
                }
                else
                {
                    node = null;
                }
            }

            return(node);
        }
Beispiel #18
0
        public bool Add(TKey[] point, TValue value)
        {
            var nodeToAdd = new KdTreeNode <TKey, TValue>(point, value);

            if (root == null)
            {
                root = new KdTreeNode <TKey, TValue>(point, value);
            }
            else
            {
                int dimension = -1;
                KdTreeNode <TKey, TValue> parent = root;

                do
                {
                    // Increment the dimension we're searching in
                    dimension = (dimension + 1) % dimensions;

                    // Does the node we're adding have the same hyperpoint as this node?
                    if (typeMath.AreEqual(point, parent.Point))
                    {
                        return(false);
                    }

                    // Which side does this node sit under in relation to it's parent at this level?
                    int compare = typeMath.Compare(point[dimension], parent.Point[dimension]);

                    if (parent[compare] == null)
                    {
                        parent[compare] = nodeToAdd;
                        break;
                    }
                    else
                    {
                        parent = parent[compare];
                    }
                }while (true);
            }

            Count++;
            return(true);
        }
Beispiel #19
0
        private KdTreeNode <TKey, TValue>[] RadialSearch(TKey[] center, TKey radius, NearestNeighbourList <KdTreeNode <TKey, TValue>, TKey> nearestNeighbours)
        {
            AddNearestNeighbours(
                root,
                center,
                HyperRect <TKey> .Infinite(dimensions, typeMath),
                0,
                nearestNeighbours,
                typeMath.Multiply(radius, radius));

            var count = nearestNeighbours.Count;

            var neighbourArray = new KdTreeNode <TKey, TValue> [count];

            for (var index = 0; index < count; index++)
            {
                neighbourArray[count - index - 1] = nearestNeighbours.RemoveFurtherest();
            }

            return(neighbourArray);
        }
Beispiel #20
0
        private void AddNodeToStringBuilder(KdTreeNode <TKey, TValue> node, StringBuilder sb, int depth)
        {
            sb.AppendLine(node.ToString());

            for (var side = -1; side <= 1; side += 2)
            {
                for (var index = 0; index <= depth; index++)
                {
                    sb.Append("\t");
                }

                sb.Append(side == -1 ? "L " : "R ");

                if (node[side] == null)
                {
                    sb.AppendLine("");
                }
                else
                {
                    AddNodeToStringBuilder(node[side], sb, depth + 1);
                }
            }
        }
Beispiel #21
0
        public KdTreeNode <TKey, TValue>[] GetNearestNeighbours(TKey[] point, int count)
        {
            if (count > Count)
            {
                count = Count;
            }

            if (count < 0)
            {
                throw new ArgumentException("Number of neighbors cannot be negative");
            }

            if (count == 0)
            {
                return(new KdTreeNode <TKey, TValue> [0]);
            }

            var neighbours = new KdTreeNode <TKey, TValue> [count];

            var nearestNeighbours = new NearestNeighbourList <KdTreeNode <TKey, TValue>, TKey>(count, typeMath);

            var rect = HyperRect <TKey> .Infinite(dimensions, typeMath);

            AddNearestNeighbours(root, point, rect, 0, nearestNeighbours, typeMath.MaxValue);

            count = nearestNeighbours.Count;

            var neighbourArray = new KdTreeNode <TKey, TValue> [count];

            for (var index = 0; index < count; index++)
            {
                neighbourArray[count - index - 1] = nearestNeighbours.RemoveFurtherest();
            }

            return(neighbourArray);
        }
Beispiel #22
0
        /*
         * 1. Search for the target
         *
         *   1.1 Start by splitting the specified hyper rect
         *       on the specified node's point along the current
         *       dimension so that we end up with 2 sub hyper rects
         *       (current dimension = depth % dimensions)
         *
         *	 1.2 Check what sub rectangle the the target point resides in
         *	     under the current dimension
         *
         *   1.3 Set that rect to the nearer rect and also the corresponding
         *       child node to the nearest rect and node and the other rect
         *       and child node to the further rect and child node (for use later)
         *
         *   1.4 Travel into the nearer rect and node by calling function
         *       recursively with nearer rect and node and incrementing
         *       the depth
         *
         * 2. Add leaf to list of nearest neighbours
         *
         * 3. Walk back up tree and at each level:
         *
         *    3.1 Add node to nearest neighbours if
         *        we haven't filled our nearest neighbour
         *        list yet or if it has a distance to target less
         *        than any of the distances in our current nearest
         *        neighbours.
         *
         *    3.2 If there is any point in the further rectangle that is closer to
         *        the target than our furtherest nearest neighbour then travel into
         *        that rect and node
         *
         *  That's it, when it finally finishes traversing the branches
         *  it needs to we'll have our list!
         */

        private void AddNearestNeighbours(
            KdTreeNode <TKey, TValue> node,
            TKey[] target,
            HyperRect <TKey> rect,
            int depth,
            NearestNeighbourList <KdTreeNode <TKey, TValue>, TKey> nearestNeighbours,
            TKey maxSearchRadiusSquared)
        {
            if (node == null)
            {
                return;
            }

            // Work out the current dimension
            int dimension = depth % dimensions;

            // Split our hyper-rect into 2 sub rects along the current
            // node's point on the current dimension
            var leftRect = rect.Clone();

            leftRect.MaxPoint[dimension] = node.Point[dimension];

            var rightRect = rect.Clone();

            rightRect.MinPoint[dimension] = node.Point[dimension];

            // Which side does the target reside in?
            int compare = typeMath.Compare(target[dimension], node.Point[dimension]);

            var nearerRect  = compare <= 0 ? leftRect : rightRect;
            var furtherRect = compare <= 0 ? rightRect : leftRect;

            var nearerNode  = compare <= 0 ? node.LeftChild : node.RightChild;
            var furtherNode = compare <= 0 ? node.RightChild : node.LeftChild;

            // Let's walk down into the nearer branch
            if (nearerNode != null)
            {
                AddNearestNeighbours(
                    nearerNode,
                    target,
                    nearerRect,
                    depth + 1,
                    nearestNeighbours,
                    maxSearchRadiusSquared);
            }

            TKey distanceSquaredToTarget;

            // Walk down into the further branch but only if our capacity hasn't been reached
            // OR if there's a region in the further rect that's closer to the target than our
            // current furtherest nearest neighbour
            TKey[] closestPointInFurtherRect = furtherRect.GetClosestPoint(target, typeMath);
            distanceSquaredToTarget = typeMath.DistanceSquaredBetweenPoints(closestPointInFurtherRect, target);

            if (typeMath.Compare(distanceSquaredToTarget, maxSearchRadiusSquared) <= 0)
            {
                if (nearestNeighbours.IsCapacityReached)
                {
                    if (typeMath.Compare(distanceSquaredToTarget, nearestNeighbours.GetFurtherestDistance()) < 0)
                    {
                        AddNearestNeighbours(
                            furtherNode,
                            target,
                            furtherRect,
                            depth + 1,
                            nearestNeighbours,
                            maxSearchRadiusSquared);
                    }
                }
                else
                {
                    AddNearestNeighbours(
                        furtherNode,
                        target,
                        furtherRect,
                        depth + 1,
                        nearestNeighbours,
                        maxSearchRadiusSquared);
                }
            }

            // Try to add the current node to our nearest neighbours list
            distanceSquaredToTarget = typeMath.DistanceSquaredBetweenPoints(node.Point, target);

            if (typeMath.Compare(distanceSquaredToTarget, maxSearchRadiusSquared) <= 0)
            {
                nearestNeighbours.Add(node, distanceSquaredToTarget);
            }
        }
Beispiel #23
0
        private TValue FindMinimum(KdTreeNode <TValue> node, int splittingDimension, int depth)
        {
            if (node == null)
            {
                return(default(TValue));
            }

            var dimension = depth % this.dimensionality;

            if (dimension == splittingDimension)
            {
                // Find minimum value in left sub-tree.
                if (node.LeftChild == null)
                {
                    return(node.Value);
                }
                else
                {
                    return(FindMinimum(node.LeftChild, splittingDimension, depth + 1));
                }
            }
            else
            {
                /*
                 * <ADDED> was added after I received a friendly email with possible bug in the code.
                 *
                 * Quote
                 *
                 * "I came across a strange bug you may not have discovered.
                 * In your Findmin method, if the TValue is a value type not a reference type all hell breaks loose when removing nodes.
                 * Also, I noted that you cannot actually remove all the nodes from your data structure
                 * (the root always remains) but I wouldn't call that a bug."
                 *
                 */

                // Find node with minimum value in sub-tree of current node.
                var nodeLocation  = this.locationGetter(node.Value);
                var leftMinValue  = FindMinimum(node.LeftChild, splittingDimension, depth + 1);
                var rightMinValue = FindMinimum(node.RightChild, splittingDimension, depth + 1);

                var leftMinValueBetter = leftMinValue != null &&
                                         fieldComparer.Compare(this.locationGetter(leftMinValue)[splittingDimension],
                                                               nodeLocation[splittingDimension]) < 0;

                // <ADDED>
                if (leftMinValue.Equals(default(TValue)))
                {
                    leftMinValueBetter = false;
                }
                //  </ADDED>

                var rightMinValueBetter = rightMinValue != null &&
                                          fieldComparer.Compare(this.locationGetter(rightMinValue)[splittingDimension],
                                                                nodeLocation[splittingDimension]) < 0;

                // <ADDED>
                if (rightMinValue.Equals(default(TValue)))
                {
                    rightMinValueBetter = false;
                }
                //  </ADDED>

                if (leftMinValueBetter && !rightMinValueBetter)
                {
                    return(leftMinValue);
                }
                else if (rightMinValueBetter)
                {
                    return(rightMinValue);
                }
                else
                {
                    return(node.Value);
                }
            }
        }
 public int Compare(KdTreeNode <TKey, TValue> x, KdTreeNode <TKey, TValue> y)
 {
     return(typeComparer.Compare(x.Points[byDimension], y.Points[byDimension]));
 }
        /// <summary>
        /// Add new node to tree
        /// </summary>
        /// <param name="point">Key</param>
        /// <param name="value">Value</param>
        /// <returns>Return <code>true</code> if node was added</returns>
        public bool Add(TKey[] point, TValue value)
        {
            var nodeToAdd = new KdTreeNode <TKey, TValue>(point, value);

            if (root == null)
            {
                root = nodeToAdd;
            }
            else
            {
                int dimension = -1;
                var navParent = root;
                do
                {
                    dimension = (dimension + 1) % dimensions;
                    if (isNode(dimension))
                    {
                        var parent = (KdTreeNode <TKey, TValue>)navParent;
                        if (typeMath.AreEqual(point, parent.Points))
                        {
                            switch (AddDuplicateBehavior)
                            {
                            case AddDuplicateBehavior.Skip:
                                return(false);

                            case AddDuplicateBehavior.Continue:
                                break;

                            case AddDuplicateBehavior.Error:
                                throw new DuplicateNodeError();

                            case AddDuplicateBehavior.Update:
                                if (OnNodeUpdate != null)
                                {
                                    if (OnNodeUpdate.Invoke(this, parent, nodeToAdd))
                                    {
                                        return(true);
                                    }
                                }
                                else
                                {
                                    parent.Value = value;
                                    return(true);
                                }

                                break;

                            default:
                                // Should never happen
                                throw new Exception("Unexpected AddDuplicateBehavior");
                            }
                        }
                    }
                    // Which side does this node sit under in relation to it's parent at this level?
                    int compare = typeMath.Compare(point[dimension], navParent.Point);

                    if (navParent[compare] == null)
                    {
                        if (isNavNode(dimension + 1))
                        {
                            navParent[compare] = new KdTreeNavNode <TKey>(point[(dimension + 1) % dimensions]);
                            navParent          = navParent[compare];
                        }
                        else
                        {
                            navParent[compare] = nodeToAdd;
                            break;
                        }
                    }
                    else
                    {
                        navParent = navParent[compare];
                    }
                } while (true);
            }

            Count++;
            return(true);
        }