private void nearest(KDTreeNode <T> current, double[] position, KdTreeNodeCollection <T> list) { // Compute distance from this node to the point double d = _distance(position, current.Position); if (current.IsLeaf) { // Base: node is leaf list.Add(current, d); } else { // Check for leafs on the opposite sides of // the subtrees to nearest possible neighbors. // Prepare for recursion. The following null checks // will be used to avoid function calls if possible double value = position[current.Axis]; double median = current.Position[current.Axis]; if (value < median) { if (current.Left != null) { nearest(current.Left, position, list); } list.Add(current, d); if (current.Right != null) { if (Math.Abs(value - median) <= list.Distance.Max) { nearest(current.Right, position, list); } } } else { if (current.Right != null) { nearest(current.Right, position, list); } list.Add(current, d); if (current.Left != null) { if (Math.Abs(value - median) <= list.Distance.Max) { nearest(current.Left, position, list); } } } } }
/// <summary> /// Retrieves a fixed point of nearest points to a given point. /// </summary> /// /// <param name="position">The queried point.</param> /// <param name="neighbors">The number of neighbors to retrieve.</param> /// /// <returns>A list of neighbor points, ordered by distance.</returns> /// public KdTreeNodeCollection <T> Nearest(double[] position, int neighbors) { var list = new KdTreeNodeCollection <T>(size: neighbors); if (root != null) { nearest(root, position, list); } return(list); }
/// <summary> /// Retrieves the nearest points to a given point within a given radius. /// </summary> /// /// <param name="position">The queried point.</param> /// <param name="radius">The search radius.</param> /// <param name="maximum">The maximum number of neighbors to retrieve.</param> /// /// <returns>A list of neighbor points, ordered by distance.</returns> /// public KdTreeNodeCollection <T> Nearest(double[] position, double radius, int maximum) { var list = new KdTreeNodeCollection <T>(maximum); if (root != null) { nearest(root, position, radius, list); } return(list); }
/// <summary> /// Retrieves a fixed point of nearest points to a given point. /// </summary> /// /// <param name="position">The queried point.</param> /// <param name="neighbors">The number of neighbors to retrieve.</param> /// <param name="maxLeaves">The maximum number of leaf nodes that can /// be visited before the search finishes with an approximate answer.</param> /// /// <returns>A list of neighbor points, ordered by distance.</returns> /// public KdTreeNodeCollection <T> ApproximateNearest(double[] position, int neighbors, int maxLeaves) { var list = new KdTreeNodeCollection <T>(size: neighbors); if (root != null) { int visited = 0; approximate(root, position, list, maxLeaves, ref visited); } return(list); }
private bool approximate(KDTreeNode <T> current, double[] position, KdTreeNodeCollection <T> list, int maxLeaves, ref int visited) { // Compute distance from this node to the point double d = _distance(position, current.Position); if (current.IsLeaf) { // Base: node is leaf list.Add(current, d); visited++; if (visited > maxLeaves) { return(true); } } else { // Check for leafs on the opposite sides of // the subtrees to nearest possible neighbors. // Prepare for recursion. The following null checks // will be used to avoid function calls if possible double value = position[current.Axis]; double median = current.Position[current.Axis]; if (value < median) { if (current.Left != null) { if (approximate(current.Left, position, list, maxLeaves, ref visited)) { return(true); } } list.Add(current, d); if (current.Right != null) { if (Math.Abs(value - median) <= list.Distance.Max) { if (approximate(current.Right, position, list, maxLeaves, ref visited)) { return(true); } } } } else { if (current.Right != null) { approximate(current.Right, position, list, maxLeaves, ref visited); } list.Add(current, d); if (current.Left != null) { if (Math.Abs(value - median) <= list.Distance.Max) { if (approximate(current.Left, position, list, maxLeaves, ref visited)) { return(true); } } } } } return(false); }