Taking d
as the number of dimensions and r
as the radius, I know at least two different approaches you can use:
Using a spatial hash:
Imagine the problem space divided in hypercubes by a grid of size s
such that s = r / sqrt(d)
.
The interesting thing about s = r / sqrt(d)
is that any two points inside a hypercube of that size are guaranteed to be at a distance equal or less than r
.
You can numerate the grid divisions so that every hypercube can be identified by the tuple formed by the indexes of one of its corners. These index tuples can be used as the keys into a hash structure (the spatial hash).
Now, and this is the difficult part, you have to notice that for any hypercube of the grid A
there is a set of neighbor hypercubes N = (N1, N2, ...)
whose minimal distance to the given hypercube is equal or less than the given radius, geometrically they look like an hypersphere. You can represent the elements of the set N
as the deltas of the grid indexes relatives to A
. Note that these index deltas depend on d
only.
For instance, in the bi-dimensional case, you have the following geometrical structure:
NNN index deltas: (-1, 2) ( 0, 2) ( 1, 2)
NNNNN (-2, 1) (-1, 1) ( 0, 1) ( 1, 1) ( 2, 1)
NNANN (-2, 0) (-1, 0) ( 0, 0) ( 1, 0) ( 2, 0)
NNNNN (-2, -1) (-1, -1) ( 0, -1) ( 1, -1) ( 2, -1)
NNN (-1, -2) ( 0, -2) ( 1, -2)
So, you already have all you need to implement an efficient search for the points inside a hypersphere:
Push the input points into the spatial hash using the index tuple of the hypercube containing them as the key.
Given a point p
the way to search is to determine the hypercube where it lays A
, and then using the set of index-deltas, get the set of neighbor hypercubes N
that can potentially contain points nearer than r
.
Retrieve from the spatial hash the points belonging to the hypercubes N
, and check which ones are near enough to p
.
There are some extra optimizations that can be carried out, as not checking the points in A as they are guaranteed to be all near enough. A pre-filtering of N can be performed based on the position of p
relative to A
.
Note that selecting s = r / sqrt(d)
provides a nice compromise between having small hypercubes and a not too big set N
.
Using a k-d tree or quad/octo/...-tree:
Every time you go down one level on the tree, you check if the space it represents intersects with the query hyper-sphere. If it does, you keep going down on it, otherwise you discard it completelly from the search.