Optimal algorithm to solve this maze? - algorithm

I'm currently stuck on a challenge our lecturer gave us over at our university. We've been looking at the most popular pathfinding algorithms such as Dijkstra and A*. Although, I think this challenge exercise requires something else and it has me stumped.
A visual representation of the maze that needs solving:
Color legend
Blue = starting node
Gray = path
Green = destination node
The way it's supposed to be solved is that when movement is done, it has to be done until it collides with either the edge of the maze or an obstacle (the black borders). It would also need to be solved in the least amount of row-movements possible (in this case 7)
My question: Could someone push me in the right direction on what algorithm to look at? I think Dijkstra/A* is not the way to go, considering the shortest path is not always the correct path given the assignment.

It is still solvable with Dijkstra / A*, what needs to be changed is the configuration of neighbors.
A little background, first:
Dijkstra and A* are general path finding algorithms formulated on graphs. When, instead of a graph, we have a character moving on a grid, it might not be that obvious where the graph is. But it's still there, and one way to construct a graph would be the following:
the nodes of the graph correspond to the cells of the grid
there are edges between nodes corresponding to neighboring cells.
Actually, in most problems involving some configurations and transitions between them, it is possible to construct a corresponding graph, and apply Dijkstra/A*. Thus, it is also possible to tackle problems such as sliding puzzle, rubik's cube, etc., which apparently differ significantly from a character moving on a grid. But they have states, and transitions between states, thus it is possible to try graph search methods (these methods, especially the uninformed ones such as Dijkstra's algorithm, might not always be feasible due to the large search space, but in principle it's possible to apply them).
In the problem that you mentioned, the graph would not differ much from the one with typical character movements:
the nodes can still be the cells of the grid
there will now be edges from a node to nodes corresponding to valid movements (ending near a border or an obstacle), which, in this case, will not always coincide with the four spatial immediate neighbors of the grid cell.
As pointed by Tamas Hegedus in the comments section, it's not obvious what heuristic function should be chosen if A* is used.
The standard heuristics based on Manhattan or Euclidean distance would not be valid here, as they might over-estimate the distance to the target.
One valid heuristic would be id(row != destination_row) + id(col != destination_col), where id is the identity function, with id(false) = 0 and id(true) = 1.

Dijkstra/A* are fine. What you need is to carefully think about what you consider graph nodes and graph edges.
Standing in the blue cell (lets call it 5,5), you have three valid moves:
move one cell to the right (to 6,5)
move four cells to the left (to 1,5)
move five cells up (to 5,1)
Note that you can't go from 5,5 to 4,5 or 5,4. Apply the same reasoning to new nodes (eg from 5,1 you can go to 1,1, 10,1 and 5,5) and you will get a graph on which you run your Dijkstra/A*.

You need to evaluate every possible move and take the move that results with the minimum distance. Something like the following:
int minDistance(int x, int y, int prevX, int prevY, int distance) {
if (CollionWithBorder(x, y) // can't take this path
return int.MAX_VALUE;
if (NoCollionWithBorder(x, y) // it's OK to take this path
{
// update the distance only when there is a long change in direction
if (LongDirectionChange(x, y, prevX, prevY))
distance = distance + 1;
)
if (ReachedDestination(x, y) // we're done
return distance;
// find the path with the minimum distance
return min(minDistance(x, y + 1, x, y, distance), // go right
minDistance(x + 1, y, x, y, distance), // go up
minDistance(x - 1, y, x, y, distance), // go down
minDistance(x, y - 1, x, y, distance)); // go left
}
bool LongDirectionChange(x, y, prevX, prevY) {
if (y-2 == prevY && x == prevX) ||(y == prevY && x-2 == prevX)
return true;
return false;
}
This is assuming diagonal moves are not allowed. If they are, add them to the min() call:
minDistance(x + 1, y + 1, distance), // go up diagonally to right
minDistance(x - 1, y - 1, distance), // go down diagonally to left
minDistance(x + 1, y - 1, distance), // go up diagonally to left
minDistance(x - 1, y + 1, distance), // go down diagonally to right

Related

Cover a polygonal line using the least given rectangles while keeping her continuity

Given a list of points forming a polygonal line, and both height and width of a rectangle, how can I find the number and positions of all rectangles needed to cover all the points?
The rectangles should be rotated and may overlap, but must follow the path of the polyline (A rectangle may contain multiple segments of the line, but each rectangle must contain a segment that is contiguous with the previous one.)
Do the intersections on the smallest side of the rectangle, when it is possible, would be much appreciated.
All the solutions I found so far were not clean, here is the result I get:
You should see that it gives a good render in near-flat cases, but overlaps too much in big curbs. One rectangle could clearly be removed if the previous were offset.
Actually, I put a rectangle centered at width/2 along the line and rotate it using convex hull and modified rotating calipers algorithms, and reiterate starting at the intersection point of the previous rectangle and the line.
You may observe that I took inspiration from the minimum oriented rectangle bounding box algorithm, for the orientation, but it doesn't include the cutting aspect, nor the fixed size.
Thanks for your help!
I modified k-means to solve this. It's not fast, it's not optimal, it's not guaranteed, but (IMHO) it's a good start.
There are two important modifications:
1- The distance measure
I used a Chebyshev-distance-inspired measure to see how far points are from each rectangle. To find distance from points to each rectangle, first I transformed all points to a new coordinate system, shifted to center of rectangle and rotated to its direction:
Then I used these transformed points to calculate distance:
d = max(2*abs(X)/w, 2*abs(Y)/h);
It will give equal values for all points that have same distance from each side of rectangle. The result will be less than 1.0 for points that lie inside rectangle. Now we can classify points to their closest rectangle.
2- Strategy for updating cluster centers
Each cluster center is a combination of C, center of rectangle, and a, its rotation angle. At each iteration, new set of points are assigned to a cluster. Here we have to find C and a so that rectangle covers maximum possible number of points. I don’t now if there is an analytical solution for that, but I used a statistical approach. I updated the C using weighted average of points, and used direction of first principal component of points to update a. I used results of proposed distance, powered by 500, as weight of each point in weighted average. It moves rectangle towards points that are located outside of it.
How to Find K
Initiate it with 1 and increase it till all distances from points to their corresponding rectangles become less than 1.0, meaning all points are inside a rectangle.
The results
Iterations 0, 10, 20, 30, 40, and 50 of updating cluster centers (rectangles):
Solution for test case 1:
Trying Ks: 2, 4, 6, 8, 10, and 12 for complete coverage:
Solution for test case 2:
P.M: I used parts of Chalous Road as data. It was fun downloading it from Google Maps. The I used technique described here to sample a set of equally spaced points.
It’s a little late and you’ve probably figured this out. But, I was free today and worked on the constraint reflected in your last edit (continuity of segments). As I said before in the comments, I suggest using a greedy algorithm. It’s composed of two parts:
A search algorithm that looks for furthermost point from an initial point (I used binary search algorithm), so that all points between them lie inside a rectangle of given w and h.
A repeated loop that finds best rectangle at each step and advances the initial point.
The pseudo code of them are like these respectively:
function getBestMBR( P, iFirst, w, h )
nP = length(P);
iStart = iFirst;
iEnd = nP;
while iStart <= iEnd
m = floor((iStart + iEnd) / 2);
MBR = getMBR(P[iFirst->m]);
if (MBR.w < w) & (MBR.h < h) {*}
iStart = m + 1;
iLast = m;
bestMBR = MBR;
else
iEnd = m - 1;
end
end
return bestMBR, iLast;
end
function getRectList( P, w, h )
nP = length(P);
rects = [];
iFirst = 1;
iLast = iFirst;
while iLast < nP
[bestMBR, iLast] = getBestMBR(P, iFirst, w, h);
rects.add(bestMBR.x, bestMBR.y, bestMBR.a];
iFirst = iLast;
end
return rects;
Solution for test case 1:
Solution for test case 2:
Just keep in mind that it’s not meant to find the optimal solution, but finds a sub-optimal one in a reasonable time. It’s greedy after all.
Another point is that you can improve this a little in order to decrease number of rectangles. As you can see in the line marked with (*), I kept resulting rectangle in direction of MBR (Minimum Bounding Rectangle), even though you can cover larger MBRs with rectangles of same w and h if you rotate the rectangle. (1) (2)

How to do Ray and Triangle Edge intersect?

I'm facing problem intersecting ray with triangle edges. Actually, I'm trying to pick/intersect with triangle, vertex, edge of a mesh using Mouse. So I made ray from the Mouse current position and then I intersect it with the mesh elements like triangle/polygon, vertex, edge etc to work with it. Basically, 3d modeling stuffs. Intersecting with triangle was easy and fun. And the vertex part was tricky.
But now, I don't know how to intersect/pick with triangle edges. I mean how I treat them when intersecting with the Mouse Ray? First I thought they can be treated like a 3D line. But eventually failed to do the Ray and the Line intersect. Searched on the Internet but not found any helpful info. Although I found some open source projects are using OpenGL built-in picking features to pick/intersect with Edge. But in my case, I can't use that. :(
My current edge picking code structure looks like the following:
void pickEdge(Ray ray, Scene scene)
{
for each object in scene
{
mesh = getMesh(object)
for each triangle in mesh
{
for each edge in triangle
{
v1 = getV1(edge)
v2 = getV2(edge)
// Do intersect with 'ray' and 'v1', 'v2'. But how?
}
}
}
}
So I'm stuck here and really need some help. Any idea, algorithm or a small help is greatly appreciated.
In your case problem of finding intersection between triangle and ray in 3D space can be boiled down to finding point location (INSIDE, OUTSIDE, ON BOUNDARY) in triangle in 2D space (plane). All you should do is project triangle on screen plane, find intersection on edge and perform reverse projection on edge. Position of point is position of mouse. The only problem is to treat degenerate cases like mapping triangle into line segment. But I think it will not be problem, because such cases can be easily coped.
Please give a look to the algorithms at the end of this page and more in general all the ones that this website offers: http://geomalgorithms.com/a05-_intersect-1.html
The first approach is to orthogonally project the edge (and the ray) to a plane perpendicular to the ray, and then to compute the distance of the projected ray to the projected edge.
Ie., first you determine two orthogonal vectors rdir1, rdir2 orthogonal to your ray.
Then you calculate the projection of your ray (its base point) to this plane, which will simply yield a 2d point rp.
Then you project the edge to that plane, by simply applying dot products:
pv1 = new Vector2(DotProduct(v1, rdir1), DotProduct(v1, rdir2))
pv2 = new Vector2(DotProduct(v2, rdir1), DotProduct(v2, rdir2))
Now you can compute the distance from this 2d line pv1, pv2 to the point rp.
Provided that the direction of the edge is taken from the view matrix's "forward" direction, then two vectors orthogonal to that would be the view matrix's left and right vectors.
Doing the above recipe will then yield something similar to projecting the edge to the screen. Hence, alternatively you could project the edge to the screen and work with those coordinates.
First of all, what is the distance between two geometric objects A and B ? It is the minimal distance between any two points on A and B, ie. dist(A,B) = min { EuclideanLength(x - y) | x in A, y in B}. (If it exists and is unique, which it does in your case.)
Here EuclideanLength((x,y,z)) = sqrt(x^2 + y^2 + z^2) as you already know. Because sqrt is strictly increasing it suffices to minimize SquareEuclideanLength((x,y,z)) = x^2 + y^2 + z^2, which greatly simplifies the problem.
In your question the objects are a line segment A := {v1 + t*(v2-v1) | 0 <= t <= 1} and a line B := {p + s*d | s is any real number}. (Don't worry that you asked about a ray, a line is really what you want.)
Now calculating the distance comes down to finding appropriate t and s such that SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) is minimal and then computing EuclideanLength(v1 + t*(v2-v1) - p - s*d) to get the real distance.
To solve this we need some analytic geometry. Because d is not zero, we can write each vector v as a sum of a part that is orthogonal to d and a part that is a multiple of d: v = Ov + Mv. For such an "orthogonal decomposition" it always holds SquareEuclideanLength(v) = SquareEuclideanLength(Ov) + SquareEuclideanLength(Mv).
Because of d = Md in the above
SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) =
SquareEuclideanLength(Ov1 + t*(Ov2-Ov1) - Op)
+ SquareEuclideanLength(Mv1 + t*(Mv2-Mv1) - Mp - s*d)
the left addend does not depend on s and however you chose t you can find an s such that the right addend is 0 ! (Remember that Mv1, Mv2, ... are multiples of d.)
Hence to find the minimum you just have to find such maps O, M as above and find the minimizer t.
Assuming that d is normalized, these are actually given by Ov := CrossProduct(v, d) and Mv := DotProduct(v, d)*d, but just believe me, that this also works if d is not normalized.
So the recipe for finding the distance is now: find 0 <= t <= 1 that minimizes
SquareEuclideanLength(Cross(v1 - p, d) + t*Cross(v2 - v1, d))
= SquareEuclideanLength(Cross(v1 - p, d))
+ 2*t*Dot(Cross(v1 - p, d), Cross(v2 - v1, d))
+ t^2 SquareEuclideanLength(Cross(v2 - v1, d)).
You will already know this formula from Point-Line distance calculation (that's what it is) and it is solved by differentiating with respect to t and equalling 0.
So the minimizer of this equation is
t = -Dot(Cross(v1 - p, d), Cross(v2 - v1, d))/SquareEuclideanLength(Cross(v2 - v1, d))
Using this t you calculate v1 + t*(v2 - v1), the point on the line segment A that is closest to line B and you can plug this into your point-line distance algorithm to find the sought after distance.
I hope this helps you !

Calculate the perimeter and area of intersecting rectangles?

I searched a lot, but I didn't find a good answer that works for this case.
We have some rectangles that are horizontal or vertical. They can be placed on the page randomly. They can overlap or have a common edge or be separate from each other.
I want to find an algorithm with O(nlogn) that can find perimeter and area of these rectangles.
These pictures may make the problem clear.
I think that interval trees might help, but I'm not sure how.
It can be done by a sweep-line algorithm.
We'll sweep an imaginary line from left to right.
We'll notice the way the intersection between the line and the set of rectangles represents a set of intervals, and that it changes when we encounter a left or right edge of a rectangle.
Let's say that the intersection doesn't change between x coordinates x1 and x2.
Then, if the length of the intersection after x1 was L, the line would have swept an area equal to (x2 - x1) * L, by sweeping from x1 to x2.
For example, you can look at x1 as the left blue line, and x1 as the right blue line on the following picture (that I stole from you and modified a bit :)):
It should be clear that the intersection of our sweep-line doesn't change between those points. However, the blue intersection is quite different from the red one.
We'll need a data structure with these operations:
insert_interval(y1, y2);
get_total_length();
Those are easily implemented with a segment tree, so I won't go into details now.
Now, the algorithm would go like this:
Take all the vertical segments and sort them by their x coordinates.
For each relevant x coordinate (only the ones appearing as edges of rectangles are important):
Let x1 be the previous relevant x coordinate.
Let x2 be the current relevant x coordinate.
Let L be the length given by our data structure.
Add (x2 - x1) * L to the total area sum.
Remove all the right edges with x = x2 segments from the data structure.
Add all the left edges with x = x2 segments to the data structure.
By left and right I mean the sides of a rectangle.
This idea was given only for computing the area, however, you may modify it to compute the perimeter. Basically you'll want to know the difference between the lengths of the intersection before and after it changes at some x coordinate.
The complexity of the algorithm is O(N log N) (although it depends on the range of values you might get as input, this is easily dealt with).
You can find more information on the broad topic of sweep-line algorithms on TopCoder.
You can read about various ways to use the segment tree on the PEG judge wiki.
Here's my (really old) implementation of the algorithm as a solution to the SPOJ problem NKMARS: implementation.
The following is O(N2) solution.
int area = 0;
FOR(triange=0->N)
{
Area = area trianlges[triangle];
FOR(int j = triangle+1 -> N)
{
area-= inter(triangle , j)
}
}
return area;
int inter(tri a,tri b)
{
if ( ( min(a.highY ,b.highY) > max(a.lowerY, b.lowerY) ) && ( min(a.highX ,b.highX) > max(a.lowerX, b.lowerX) ) )
return ( min(a.highY ,b.highY) - max(a.lowerY, b.lowerY) ) * ( min(a.highX ,b.highX) - max(a.lowerX, b.lowerX) )
else return 0;
}

Algorithm for arranging Cartesian points

I have few Cartesian points of the form : (x,y)
where x and y both are non-negative integers.
For e.g.
(0,0) , (1,1), (0,1)
I need an algorithm to arrange the above points
in such a way that going from one point to other
changes either x or y by 1.
In other words, I would like to avoid
diagonal movement.
So, the above mentioned points will be arranged like :
(0,0), (0,1), (1,1).
Similarly for (0,0),(1,1),(0,2)
there is no such arrangement possible.
I am not sure about what to call it
but I would call it Manhattan ordering.
Can anyone help?
If you are looking for an arrangement that does not repeat vertices:
What you seem to be looking for is a Hamiltonian Path in a Grid Graph.
This is known to be NP-Complete for general Grid Graphs, see Hamilton Paths in Grid Graphs.
So you can probably try your luck with any of the approximate/heuristic/etc algorithms known for Hamiltonian Path/Euclidean Traveling Salesman Problem.
If you are looking for an arrangement that can repeat, but want the minimum possible number of points in the arrangement:
This is again NP-Complete. The above problem can be reduced to it. This is because the minimum possible walk has n vertices if and only if the graph has a hamiltonian path.
If you are just looking for some arrangement of points,
Then all you need to do is check if the graph is connected. If it is not connected, there can be no such arrangement.
You can do a depth first search to figure that out. The depth first search will also give you such an arrangement in case the graph is connected.
If you want something closer to optimal (but in reasonably fast time), you can probably use approximation algorithms for the Euclidean Traveling Salesman problem.
You can construct a graph with the vertices being your points, and the edges being the valid steps.
What you're then looking for is a Hamiltonian path for this graph. This, in its general form, is an NP-complete problem, which means there is no known efficient solution (i.e. one that scales well with the number of points). Wikipedia describes a randomized algorithm that is "fast on most graphs" and might be of use:
Start from a random vertex, and continue if there is a neighbor not visited. If there are no more unvisited neighbors, and the path formed isn't Hamiltonian, pick a neighbor uniformly at random, and rotate using that neighbor as a pivot. (That is, add an edge to that neighbor, and remove one of the existing edges from that neighbor so as not to form a loop.) Then, continue the algorithm at the new end of the path.
A more efficient solution might exist for this particular situation, though.
Think of it as a graph where each node as at most four edges. Then do depth/breadth-first search.
This could be simplified as minimizing the distance between each consecutive point. Going from (0,0) to (0,1) is simply 1 unit, but going from (0,0) to (1,1) is actually sqrt(2). So if you arrange the points into a graph, and then perform a simple minimum-total-distance traversal (traveling salesman), it should arrange them correctly.
Edit: If you never want a step that would be larger than 1, simply do not add any edges that are greater than 1. The traversal will still work correctly, and ignore any paths that require a movement > 1.
Edit 2: To clarify further, you can use any edge selection algorithm you wish. If you're ok with it moving 2 spaces, as long as the space is not diagonal, then you may choose to put an edge between (0,2) and (0,4). The minimum distance algorithm will still work. Simply place the edges in a smart way, and you can use any number of selection criteria to determine the outcome.
One way to do this is to create two sorted lists of the coordinates. One sorted by x and one sorted by y. Then, recursively find a solution.
Code coming (not sure what language yet; maybe pseudocode?)... Edit - nevermind, since my answer isn't as good as some of the others anyways.
How about a brute force recursive REXX routine... Try all possible
paths and print those that work out.
/* rexx */
point. = 0 /* Boolean for each existing point */
say 'Enter origin x and y coordinate:'
pull xo yo
point.xo.yo = 1 /* Point exists... */
say 'Enter destination x and y coordinate:'
pull xd yd
point.xd.yd = 1 /* Point exists... */
say 'Enter remaining x and y coordinates, one pair per line:'
do forever
pull x y
if x = '' then leave
point.x.y = 1
end
path = ''
call findpath xo yo path
say 'All possible paths have been displayed'
return
findpath: procedure expose point. xd yd
arg x y path
if \point.x.y then return /* no such point */
newpoint = '(' || x y || ')'
if pos(newpoint, path) > 0 then return /* abandon on cycle */
if x = xd & y = yd then /* found a path */
say path newpoint
else do /* keep searching */
call findpath x+1 y path newpoint
call findpath x-1 y path newpoint
call findpath x y+1 path newpoint
call findpath x y-1 path newpoint
end
return
Example session:
Path.rex
Enter origin x and y coordinate:
0 0
Enter destination x and y coordinate:
2 2
Enter remaining x and y coordinates, one pair per line:
0 1
1 1
2 1
1 2
(0 0) (0 1) (1 1) (2 1) (2 2)
(0 0) (0 1) (1 1) (1 2) (2 2)
All possible paths have been displayed
Don't try this on anything big though - could take a very long time! But then the question never mentioned anything about being an optimal solution.

Count number of points inside a circle fast

Given a set of n points on plane, I want to preprocess these points somehow faster than O(n^2) (O(nlog(n)) preferably), and then be able to answer on queries of the following kind "How many of n points lie inside a circle with given center and radius?" faster than O(n) (O(log(n) preferably).
Can you suggest some data structure or algorithm I can use for this problem?
I know that such types of problems are often solved using Voronoi diagrams, but I don't know how to apply it here.
Build a spatial subdivision structure such as a quadtree or KD-tree of the points. At each node store the amount of points covered by that node. Then when you need to count the points covered by the lookup circle, traverse the tree and for each subdivision in a node check if it is fully outside the circle, then ignore it, if it is fully inside the circle then add its count to the total if it intersects with the circle, recurse, when you get to the leaf, check the point(s) inside the leaf for containment.
This is still O(n) worst case (for instance if all the points lie on the circle perimeter) but average case is O(log(n)).
Build a KD-tree of the points, this should give you much better complexity than O(n), on average O(log(n)) I think.
You can use a 2D tree since the points are constrained to a plane.
Assuming that we have transformed the problem into 2D, we'll have something like this for the points:
struct Node {
Pos2 point;
enum {
X,
Y
} splitaxis;
Node* greater;
Node* less;
};
greater and less contains points with greater and lesser coordinates respectively along the splitaxis.
void
findPoints(Node* node, std::vector<Pos2>& result, const Pos2& origin, float radius) {
if (squareDist(origin - node->point) < radius * radius) {
result.push_back(node->point);
}
if (!node->greater) { //No children
return;
}
if (node->splitaxis == X) {
if (node->point.x - origin.x > radius) {
findPoints(node->greater, result, origin radius);
return;
}
if (node->point.x - origin.x < -radius) {
findPoints(node->less, result, origin radius);
return;
}
findPoints(node->greater, result, origin radius);
findPoints(node->less, result, origin radius);
} else {
//Same for Y
}
}
Then you call this function with the root of the KD-tree
If my goal is speed, and the number of points weren't huge (millions,) I'd focus on memory footprint as much as algorithmic complexity.
An unbalanced k-d tree is best on paper, but it requires pointers, which can expand memory footprint by 3x+, so it is out.
A balanced k-d tree requires no storage, other than for an array with one scalar for each point. But it too has a flaw: the scalars can not be quantized - they must be the same 32 bit floats as in the original points. If they are quantized, it is no longer possible to guarantee that a point which appears earlier in the array is either on the splitting plane, or to its left AND that a point which appears later in the array is either on the splitting plane, or to its right.
There is a data structure I developed that addresses this problem. The Synergetics folks tell us that volume is experientially four-directional. Let's say that a plane is likewise experientially three-directional.
We're accustomed to traversing a plane by the four directions -x, +x, -y, and +y, but it's simpler to use the three directions a, b, and c, which point at the vertices of an equilateral triangle.
When building the balanced k-d tree, project each point onto the a, b, and c axes. Sort the points by increasing a. For the median point, round down, quantize and store a. Then, for the sub-arrays to the left and right of the median, sort by increasing b, and for the median points, round down, quantize, and store b. Recurse and repeat until each point has stored a value.
Then, when testing a circle (or whatever) against the structure, first calculate the maximum a, b, and c coordinates of the circle. This describes a triangle. In the data structure we made in the last paragraph, compare the median point's a coordinate to the circle's maximum a coordinate. If the point's a is larger than the circle's a, we can disqualify all points after the median. Then, for the sub-arrays to the left and right (if not disqualified) of the median, compare the circle's b to the median point's b coordinate. Recurse and repeat until there are no more points to visit.
This is similar in theme to the BIH data structure, but requires no intervals of -x and +x and -y and +y, because a, b, and c are just as good at traversing the plane, and require one fewer direction to do it.
Assuming you have a set of points S in a cartesian plane with coordinates (xi,yi), given an arbitrary circle with center (xc,yc) and radius r you want to find all the points contained within that circle.
I will also assume that the points and the circle may move so certain static structures that can speed this up won't necessarily be appropriate.
Three things spring to mind that can speed this up:
Firstly, you can check:
(xi-xc)^2 + (yi-yc)^2 <= r^2
instead of
sqrt((xi-xc)^2 + (yi-yc)^2) <= r
Secondly, you can cull the list of points somewhat by remembering that a point can only be within the circle if:
xi is in the range [xc-r,xc+r]; and
yi is in the range [yc-r,yc+r]; and
This is known as a bounding box. You can use it as either an approximation or to cut down your list of points to a smaller subset to check accurately with the first equation.
Lastly, sort your points in either x or y order and then you can do a bisection search to find the set of points that are possibly within your bounding box, further cutting down on unnecessary checks.
I used Andreas's code but it contains a bug. For example I had two points on the plane [13, 2], [13, -1] and my origin point was [0, 0] with a radius of 100. It finds only 1 point. This is my fix:
void findPoints(Node * root, vector<Node*> & result, Node * origin, double radius, int currAxis = 0) {
if (root) {
if (pow((root->coords[0] - origin->coords[0]), 2.0) + pow((root->coords[1] - origin->coords[1]), 2.0) < radius * radius) {
result.push_back(root);
}
if (root->coords[currAxis] - origin->coords[currAxis] > radius) {
findPoints(root->right, result, origin, radius, (currAxis + 1) % 2);
return;
}
if (origin->coords[currAxis] - root->coords[currAxis] > radius) {
findPoints(root->left, result, origin, radius, (currAxis + 1) % 2);
return;
}
findPoints(root->right, result, origin, radius, (currAxis + 1) % 2);
findPoints(root->left, result, origin, radius, (currAxis + 1) % 2);
}
}
The differnce is Andreas checked for now children with just if (!root->greater) which is not complete. I on the other hand don't do that check, I simply check if the root is valid.
Let me know if you find a bug.
depending on how much precomputing time you have, you could build a tree like this:
first node branches are x-values, below them are y-value nodes, and below them are radius value nodes. at each leaf is a hashset of points.
when you want to compute the points at x,y,r: go through your tree and go down the branch that matches your x,y values the closest. when you get down to the root level, you need to do a little match (constant time stuff), but you can find a radius such that all the points in that circle (defined by the path in the tree) are inside the circle specified by x,y,r, and another circle (same x_tree,y_tree in the tree as before, but different r_tree) such that all of the points in the original circle (specified by x,y,r) are in that circle.
from there, go through all the points in the larger of the two tree circles: if a point is in the smaller circle add it to the results, if not, run the distance check on it.
only problem is that it takes a very long time to precompute the tree. although, you can specify the amount of time you want to spend by changing how many x,y, and r branches you want to have in your tree.

Resources