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); }
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); }
/* * 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); } }
/// <summary> /// Performs a radial search up to a maximum count. /// </summary> /// <param name="center">Center point</param> /// <param name="radius">Radius to find neighbours within</param> /// <param name="count">Maximum number of neighbours</param> public KdTreeNode <TKey, TValue>[] RadialSearch(TKey[] center, TKey radius, int count) { var nearestNeighbours = new NearestNeighbourList <KdTreeNode <TKey, TValue>, TKey>(count, typeMath); return(RadialSearch(center, radius, nearestNeighbours)); }