public HyperRect <T> Clone() { var rect = new HyperRect <T> { MinPoint = this.MinPoint, MaxPoint = this.MaxPoint }; return(rect); }
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); }
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); }
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); }
/* * 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); } }