Build and search k-dimensional trees in 2, 3, and K dimensions. This KdTree is balanced, in that splits are made along the dimension with the largest variance. A quickselect is used to quickly find the median in each splitting dimension as the splitting value. The ends of each branch contain multiple leaves to prevent tail recursion. An in-depth example is given below on how to use all the aspects of the KdTree and KdTreeSearch classes.
Important: Once a tree has been built with a set, do not change their values. The KdTree does NOT make a copy of the input values used to build it. Important: Generating the tree does not modify the values used to build it.
The KdTree object can be initialized on assignment by entering point co-ordinates. To build a 2-D tree, you can use two 1-D arrays as the x, y, co-ordinates, and optionally a third 1-D array to build a 3-D tree.
use m_KdTree type(KdTree) :: tree tree = KdTree(x, y, [z])
Or you can build a k-dimensional tree using a 2-D array, where the first dimension is the number of items, and the second is the number of dimensions, k.
use m_KdTree type(KdTree) :: tree tree = KdTree(D)
After the tree is initialized, a search class can be used to perform search for the nearest neighbour, the k nearest neighbours, all neighbours within a radius, k nearest within a radius, and items within upper and lower bounds in each dimension. The searches are thread safe and can be used in a parallel region.
After the KdTree is built, various queries can be carried out. Searches that return multiple values are called using the argDynamicArray within coretran. The [[m_dArgDynamicArray]] contains an integer index containing the indices into the co-ordinates that are closest, and a double precision that contains the distance from the query point to those points.
use m_dArgDynamicArray use m_KdTree type(KdTreeSearch) :: search integer(i32) :: i type(dArgDynamicArray) :: da ! Nearest Neighbour to (0, 0), for 3D add z, and zQuery i = search%nearest(tree, x, y, [z], xQuery = 0.d0, yQuery = 0.d0, [zQuery = 0.d0]) ! K-Nearest to (0, 0), for 3D add z, and zQuery da = search%kNearest(tree, x, y, [z], xQuery = 0.d0, yQuery = 0.d0, [zQuery = 0.d0], k = 10) ! Search for all points within a given distance da = search%kNearest(tree, x, y, [z], xQuery = 0.d0, yQuery = 0.d0, [zQuery = 0.d0], radius = 10.d0) ! Search for all k points within a given distance da = search%kNearest(tree, x, y, [z], xQuery = 0.d0, yQuery = 0.d0, [zQuery = 0.d0], k = 10, radius = 10.d0)
program kdTree_test use variableKind, only: i32, r64 use m_allocate, only: allocate use m_deallocate, only: deallocate use m_random, only: rngNormal use m_KdTree, only: KdTree, KdTreeSearch use m_dArgDynamicArray, only: dArgDynamicArray use m_string, only: str implicit none real(r64), allocatable :: x(:), y(:), z(:), D(:,:) integer(i32) :: ia, N type(KdTree) :: tree type(KdSearch) :: search type(dArgDynamicArray) :: da !====================================================================! ! 2D KdTree example !====================================================================! ! Create some random points in space N = 1d6 call allocate(x, N) call allocate(y, N) call rngNormal(x) call rngNormal(y) ! Build the tree tree = KdTree(x, y) ! Get the nearest neighbour to (0, 0) ia = search%kNearest(tree, x, y, xQuery = 0.d0, yQuery = 0.d0) write(*,'(a)') 'Nearest point to the query location: '//str(x(ia))//str(y(ia)) ! Get the 10 nearest neighbours to the query da = search%kNearest(tree, x, y, xQuery = 0.d0, yQuery = 0.d0, k = 10) write(*,'(a)') 'The 10 nearest neighbour indices and distances:' call da%print() ! Find all the points within a 1.d0 da = search%kNearest(tree, x, y, xQuery = 0.d0, yQuery = 0.d0, radius = 1.d0) write(*,'(a)') 'The points within a distance of 1.d0' call da%print() Deallocate any tree memory call tree%deallocate() !====================================================================! ! 3D KdTree example !====================================================================! ! Create the third dimension call allocate(z, N) call rngNormal(z) ! Build the tree tree = KdTree(x, y, z) ! Get the nearest neighbour to (0, 0, 0) ia = search%kNearest(tree, x, y, z, xQuery = 0.d0, yQuery = 0.d0, zQuery = 0.d0) write(*,'(a)')'Nearest point to the query location: '//str(x(ia))//str(y(ia))//str(z(ia)) ! Get the 10 nearest neighbours to the query da = search%kNearest(tree, x, y, z, xQuery = 0.d0, yQuery = 0.d0, zQuery = 0.d0, k = 10) write(*,'(a)') 'The 10 nearest neighbour indices and distances:' call da%print() ! Find all the points within a 1.d0 da = search%kNearest(tree, x, y, z, xQuery = 0.d0, yQuery = 0.d0, zQuery = 0.d0, radius = 1.d0) write(*,'(a)') 'The points within a distance of 1.d0' call da%print() Deallocate any tree memory call tree%deallocate() !====================================================================! ! KD KdTree example !====================================================================! call allocate(D, [N, 3]) D(:,1) = x D(:,2) = y D(:,3) = z ! Build the tree tree = KdTree(D) ! Get the nearest neighbour to (0, 0, 0) ia = search%kNearest(tree, D, query = [0.d0, 0.d0, 0.d0]) write(*,'(a)')'Nearest point to the query location: '//str(D(ia, 1))//str(D(ia, 2))//str(D(ia, 3)) ! Get the 10 nearest neighbours to the query da = search%kNearest(tree, D, query = [0.d0, 0.d0, 0.d0], k = 10) write(*,'(a)') 'The 10 nearest neighbour indices and distances:' call da%print() ! Find all the points within a 1.d0 da = search%kNearest(tree, D, query = [0.d0, 0.d0, 0.d0], radius = 1.d0) write(*,'(a)') 'The points within a distance of 1.d0' call da%print() Deallocate any tree memory call tree%deallocate() call deallocate(x) call deallocate(y) call deallocate(z) call deallocate(D) end program
Overloaded Initializer for a KdTree.
Overloaded by interface KdTree
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
real(kind=r64), | intent(in) | :: | x(:) | x-coordinates of the points |
||
real(kind=r64), | intent(in) | :: | y(:) | y-coordinates of the points |
KdTree Class
Overloaded by interface KdTree
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
real(kind=r64), | intent(in) | :: | x(:) | x-coordinates of the points |
||
real(kind=r64), | intent(in) | :: | y(:) | y-coordinates of the points |
||
real(kind=r64), | intent(in) | :: | z(:) | z-coordinates of the points |
KdTree Class
Overloaded by interface KdTree
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
real(kind=r64), | intent(in) | :: | D(:,:) | Coordinates of the points, the k columns contain the k dimensional values. |
KdTree Class
KdTree in 2, 3, or N dimensions. See m_KdTree for more information on how to use this class.
Overloaded Initializer for a KdTree.
public function init2D_KdTree(x, y) | Overloaded by interface KdTree |
public function init3D_KdTree(x, y, z) | Overloaded by interface KdTree |
public function initKD_KdTree(D) | Overloaded by interface KdTree |
procedure, public :: deallocate => deallocate_KdTree | kdTree%deallocate() - deallocate the recursive pointers |
Class to search a KdTree. See m_KdTree for more information on how to use this class.
generic, public :: nearest => nearest2D, nearest3D, nearestKD | KdTreeSearch%nearest() - Perform a nearest neighbour search |
generic, public :: kNearest => kNearest2D, kNearest3D, kNearestKD | KdTreeSearch%kNearest() - Perform a k nearest neighbour search or a radius search. |
generic, public :: rangeSearch => rangeSearch2D, rangeSearch3D, rangeSearchKD | KdTreeSearch%rangeSearch() - Find all points within axis aligned lower and upper bounds |