The simplest solution is to rescale the data. Suppose we have a distance limit of $r_x = 2$ and $r_y = 1$ and a point set
data = {{x1,y1}, {x2,y2}, ...}
Instead of working with data
and these two radii, work with a single radius $r=1$ and the dataset
dataScaled = {{0.5 x1, y1}, {0.5 x2, y2}, ...}
Finally, transform the results back to the original coordinate system.
This can be generalized for arbitrary affine transformations, including rotations.
For example, let's assume that the ellipse is rotated 30 degrees and it has dimensions 2 and 1. This can be obtained from a circle by using the following transformation matrix:
backtrafo = N[RotationMatrix[30*Degree] . {{2, 0}, {0, 1}}]
Let's visualize it!
Graphics[GeometricTransformation[Circle[], AffineTransform[backtrafo]], Frame -> True]
We need to apply the reverse transformation of this on our data and use the result in Nearest
:
trafo = Inverse[backtrafo];
Nearest[trafo.# & /@ data -> data, trafo.point, {n, 1}]
This will give us the all the points within the rotated ellipse drawn around point
.
Let's test the method visually. Generate some points:
data = RandomReal[{-2, 2}, {100, 2}];
Find the points within the ellipse centred on the origin:
pointsWithin = Nearest[trafo.# & /@ data -> data, trafo.{0, 0}, {Infinity, 1}];
And finally visualize all points together with the ellipse:
Graphics[{
GeometricTransformation[Circle[], AffineTransform[backtrafo]],
Point[data], {Red, Point[pointsWithin]}}, Frame -> True]
Technical comment: An advantage of this method compared to using a DistanceFunction
is that a custom DistanceFunction
will prevent Nearest
from using a very efficient quad-tree data structure, and it will resort to a much slower pairwise-distance calculation.
Thanks to Michael E2 for suggestion on simple and efficient code!