コード例 #1
0
        private static KdTreeNode Construct(KdTree tree, Vector[] elements, int depth)
        {
            var length = elements.GetLength(0);

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

            // Sort array by dimension
            var dimension = depth % tree.Dimensionality;

            Array.Sort(
                elements,
                (a, b) => a[dimension].CompareTo(b[dimension]) // fancy delegate here.. ooh urr..
                );

            // Get median element from sorted array
            var medianIndex   = length / 2;
            var medianElement = elements[medianIndex];

            // Get sub-tree elements
            var leftElements  = elements.Take(medianIndex).ToArray();
            var rightElements = elements.Skip(medianIndex + 1).ToArray();

            // Create node and connect sub-trees
            var node = new KdTreeNode(medianElement);

            node.LeftChild  = Construct(tree, leftElements, depth + 1);
            node.RightChild = Construct(tree, rightElements, depth + 1);

            return(node);
        }
コード例 #2
0
        }                    // private empty constructor

        /// <summary>
        /// Initialises a new instance of the <see cref="KdTree"/> class with the specified root node.
        /// </summary>
        /// <param name="dimensionality">The dimensionality of the underlying <see cref="Vector"/>.</param>
        /// <param name="root">The root node of the tree. Cannot be null.</param>
        public KdTree(int dimensionality, KdTreeNode root)
            : this()
        {
            if (root == null)
            {
                throw new ArgumentNullException("root");
            }

            this.Dimensionality = dimensionality;
            this.Root           = root;
        }
コード例 #3
0
        private Vector FindNearestNeighbour(Vector location,
                                            KdTreeNode node, Vector bestValue, float bestDistance, int depth)
        {
            if (node == null) // no where left to search, return best value
            {
                return(bestValue);
            }

            var dimension = depth % this.Dimensionality;
            var nodeValue = node.Value;
            var distance  = (nodeValue - location).Norm(this.Dimensionality);

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

            // Check for best node in sub-tree of near child. i.e., which side of Node is the query point?
            var nearChildNode = (location[dimension] < nodeValue[dimension]) ?
                                node.LeftChild : node.RightChild;

            if (nearChildNode != null)
            {
                var nearBestValue    = FindNearestNeighbour(location, nearChildNode, bestValue, bestDistance, depth + 1);
                var nearBestDistance = (nearBestValue - 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 (bestDistance > Math.Abs(nodeValue[dimension] - location[dimension]))
            {
                // Check for best node in sub-tree of far child.
                var farChildNode = nearChildNode == node.LeftChild ? node.RightChild : node.LeftChild; // i.e. not the near child

                if (farChildNode != null)
                {
                    var farBestValue    = FindNearestNeighbour(location, farChildNode, bestValue, bestDistance, depth + 1);
                    var farBestDistance = (farBestValue - location).Norm(this.Dimensionality);
                    bestValue    = farBestValue;
                    bestDistance = farBestDistance;
                }
            }

            return(bestValue);
        }
コード例 #4
0
        private KdTreeNode Find(Vector value, KdTreeNode node, int depth)
        {
            if (node == null)
            {
                return(null);
            }
            if (node.Value.Equals(value))
            {
                return(node);
            }

            var dimension = depth % this.Dimensionality;
            var foundNode = (value[dimension] < node.Value[dimension]) ?
                            Find(value, node.LeftChild, depth + 1) : Find(value, node.RightChild, depth + 1);

            return(foundNode);
        }
コード例 #5
0
        private void FindInRange(Vector location,
                                 KdTreeNode node, float range, IList <Vector> valuesList, int depth)
        {
            if (node == null)
            {
                return;
            }

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

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

            // Check for nodes in sub-tree of near child.
            var nearChildNode = (location[dimension] < node.Value[dimension]) ?
                                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 ((range > Math.Abs(node.Value[dimension] - location[dimension])))
            {
                // 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);
                }
            }
        }
コード例 #6
0
        private KdTreeNode Add(Vector value, KdTreeNode node, int depth)
        {
            if (node == null)
            {
                node = new KdTreeNode(value);
            }
            else
            {
                // Check if node should be added to left or right sub-tree of current node.
                var dimension = depth % this.Dimensionality;

                if (!(value[dimension] > node.Value[dimension]))
                {
                    node.LeftChild = Add(value, node.LeftChild, depth + 1);
                }
                else
                {
                    node.RightChild = Add(value, node.RightChild, depth + 1);
                }
            }

            return(node);
        }