예제 #1
0
        public HyperRect <T> Clone()
        {
            var rect = new HyperRect <T>
            {
                MinPoint = this.MinPoint,
                MaxPoint = this.MaxPoint
            };

            return(rect);
        }
예제 #2
0
        public static HyperRect <T> Infinite(int dimensions)
        {
            var rect = new HyperRect <T>();

            rect.MinPoint = new T[dimensions];
            rect.MaxPoint = new T[dimensions];

            for (var dimension = 0; dimension < dimensions; dimension++)
            {
                rect.MinPoint[dimension] = Number <T> .MinValue;
                rect.MaxPoint[dimension] = Number <T> .MaxValue;
            }

            return(rect);
        }
예제 #3
0
        public KdTreeNode <TKey, TValue>[] RadialSearch(TKey[] center, TKey radius, int count)
        {
            var nearestNeighbours = new NearestNeighbourList <KdTreeNode <TKey, TValue>, TKey>(count);

            this.AddNearestNeighbours(this.root,
                                      center,
                                      HyperRect <TKey> .Infinite(this.dimensions),
                                      0,
                                      nearestNeighbours,
                                      (Number <TKey>)radius * radius);

            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);
        }
예제 #4
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);

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

            AddNearestNeighbours(root, point, rect, 0, nearestNeighbours, Number <TKey> .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);
        }
예제 #5
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 = target[dimension].CompareTo(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);
            }

            // 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);
            TKey   distanceSquaredToTarget   =
                closestPointInFurtherRect.Select(
                    (t, i) => (Number <TKey>)t - target[i]).
                Aggregate(default(TKey),
                          (current, val) => (Number <TKey>)current + (Number <TKey>)val * val);

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

            // Try to add the current node to our nearest neighbours list
            distanceSquaredToTarget =
                node.Point.Select((t, i) => (Number <TKey>)t - target[i]).
                Aggregate(default(TKey),
                          (current, val) => (Number <TKey>)current + (Number <TKey>)val * val);

            if (distanceSquaredToTarget.CompareTo(maxSearchRadiusSquared) <= 0)
            {
                nearestNeighbours.Add(node, distanceSquaredToTarget);
            }
        }