A-Star Search Algorithm won't find a valid path - c++

I'm trying to implement an A* algorithm for pathfinding in my 3D grid. I've been following a tutorial but I'm not getting a valid path. I've stepped through my code to find out what's going on, but I don't know how to solve the problem. For the most basic test I'm just using a 2-D grid (it's 3-D, but there's only one Z option, so basically 2-D).
Here's what it's doing:
So we start at 0,0 (orange) and want to get to 1,2 (green). First it calculates the two options for the orange square, north and east, and gets distances of 2 and 1.414 for F values of 3 and 2.414. It moves to the east square (0,1). Great. But now it calculates the two open squares from 0,1 which are 1,1 and 0,2, both of which have a g value of 2 and an h value (distance) of 1, making their F values both be 3.
Since their F values are 3 and we already have an option with an F value of 3 (1,0 from the starting point), these two options are ignored even though they are clearly the best options.
It then continues onward and switches to moving to 1,0 where it then calculates 1,1 as 3 again and 2,0 as 4.236. 1,1's f value is not bigger than our current f value though, so it's ignored and we move upward to 2,0.
2,0 can only move right so it does.
2,1 can only move down since 2,2 is an invalid square, but the f value of moving to 1,1 is saved as 3, so it's again ignored, leaving us with no valid path between 0,0 and 1,2. What am I missing?
Here's a snippet of my path loop. There's a bunch of custom structs in here, and I'm using TMap from Unreal Engine to store my closed list, but I don't think that matters to the question. Here's a quick and dirty about what these structs are:
PCell: Holds cell coordinates
PPair: Holds cell coordinates as a PCell and an F value
FVectorInt: 3-D integer vector
FPathCell: Holds parent coordinates, and f, g, and h values.
cellDetails is a 3D dynamic array of FPathCell
closedMap is a TMap with <key, value> as <IntVector, bool>
Also locationIsWalkable(FVectorInt, StepDirection) is just code that checks to see if the player can walk to a cell from a certain direction. You can ignore that part.
std::set<PPair> openList;
PPair originPair = PPair();
originPair.cell = PCell(i, j, k);
originPair.f = 0.0;
openList.insert(originPair);
bool foundDestination = false;
FPathCell destPair;
FVectorInt destCell;
while (!openList.empty() && !foundDestination)
{
iterations++;
PPair p = *openList.begin();
//Remove vertex
openList.erase(openList.begin());
//Add vertex to closed list
i = p.cell.i;
j = p.cell.j;
k = p.cell.k;
closedMap.Remove(FIntVector(i, j, k));
closedMap.Add(FIntVector(i, j, k), true);
double gNew, hNew, fNew;
//Generate movement options
//Option 1: NORTH (+X)
//Process if valid movement
if (locationIsWalkable(FVectorInt(i + 1, j, k), StepDirection::North))
{
FVectorInt check = FVectorInt(i + 1, j, k);
//If this cell is the destination
if (check == destination)
{
foundDestination = true;
//Set the parent of the destination cell
cellDetails[check.x][check.y][check.z].parent_i = i;
cellDetails[check.x][check.y][check.z].parent_j = j;
cellDetails[check.x][check.y][check.z].parent_k = k;
destPair = cellDetails[check.x][check.y][check.z];
destCell = check;
break;
}
//Else if this cell is not in the closed list
else if (!closedMap.FindRef(FIntVector(check.x, check.y, check.z)))
{
gNew = cellDetails[i][j][k].g + 1;
hNew = calculateHValue(check, destination);
fNew = gNew + hNew;
if (cellDetails[check.x][check.y][check.z].f == FLT_MAX ||
cellDetails[check.x][check.y][check.z].f > fNew) {
PPair cellPair = PPair();
cellPair.cell = PCell(check.x, check.y, check.z);
cellPair.f = fNew;
openList.insert(cellPair);
cellDetails[check.x][check.y][check.z].f = fNew;
cellDetails[check.x][check.y][check.z].g = gNew;
cellDetails[check.x][check.y][check.z].h = hNew;
cellDetails[check.x][check.y][check.z].parent_i = i;
cellDetails[check.x][check.y][check.z].parent_j = j;
cellDetails[check.x][check.y][check.z].parent_k = k;
}
}
}
//11 other movement options
}
inline bool operator<(const PPair& lhs, const PPair& rhs)
{
return lhs.f < rhs.f;
}
There's 12 movement options (north, south, east, west, up+north, down+north, etc.), but they basically all use the same code and just swap out the check vector for the appropriate movements.
Here's the tutorial I followed

Since their F values are 3 and we already have an option with an F value of 3 (1,0 from the starting point), these two options are ignored even though they are clearly the best options.
This must be your mistake. These options shall not be 'ignored', but rather 'delayed till they are the next-best options'. The way it's done is that on every iteration of A* you ought to select the open cell with the lowest F-score.
In your example, once you expand 0,1 (to get 0,2 and 1,1), your open set should look like:
(1,0):3 (1,1):3 (0,2):3
(It can also be any other permutation of these, because they have the same scores.)
Now imagine that it chooses to visit 1,0. It adds 2,0 to the queue, but 1,1 and 0,2 should still be there:
(1,1):3 (0,2):3 (2,0):4.236
Since 2,0 has a higher F-score than 1,1 or 0,2, it will not be chosen yet. Instead your algorithm shall pick 1,1 or 0,2 at this iteration, thus arriving at the destination 1,2.
As for your code, you're using an std::set for the openList, which prevents having multiple instances with the same score within the queue. You can use multiset or priority_queue to combat that. However, A* can decrease the weight of nodes in the open set, and neither data-structure allows that operation in sub-linear time. By inserting the same node multiple times (every time its score decreases), and ignoring any pops after it was closed, you'll still get a correct, though sub-optimal, algorithm.
Proper A* implementations usually use binomial or Fibonnacci heaps.
Unfortunately C++ doesn't have them. You can find libraries implementing these on the web.

Related

The minimum number of steps for a chess knight to reach a certain position on a chessboard

There is an unlimited chessboard,
from the console we enter how many examples there will be and how many chess knights are on the board, and their starting positions (that is, where they are), and the points to which the knights must go in the least number of steps.
Here's what it should look like:
2 - number of examples
1 - the number of chess knights
5 5 - the starting point
5 6 - the final point
2 - the number of chess knights
0 0 - the starting point of the first knight
1 0 - the starting point of the second knight
0 1 - the final point of the first knight
1 1 - the final point of the second knight
Answer:
3 - the answer for the first example
4 - the answer for the second example
The problem is that it doesn't work out that way, because with the first data set everything is fine, but with the second it does not work out the correct answer.
If we take the points separately, then the answer in the second data set is 6 (3 for the first knight and 3 for the second knight).
I have guesses how to solve it, but it does not work.
The conjecture is that when the second knight begins to move, it passes the same points that the first knight passed (the second example) and you probably need to write down the conditions if the first knight was already at these positions, then the second cannot pass them again.
The second conjecture is that you need to write down the conditions for the board and make it unlimited, and make the knight walk the negative values of the chessboard.
Here is a sample photo (below):
Please help, I will be very grateful !!!
#include <iostream>
#include <set>
#include <queue>
#include <climits>
using namespace std;
#define N 8
// Below arrays details all 8 possible movements
// for a knight
int row[] = { 2, 2, -2, -2, 1, 1, -1, -1 };
int col[] = { -1, 1, 1, -1, 2, -2, 2, -2 };
// Check if (x, y) is valid chess board coordinates
// Note that a knight cannot go out of the chessboard
bool valid(int x, int y)
{
if (x < 0 || y < 0 || x >= N || y >= N)
return false;
return true;
}
// queue node used in BFS
struct Node
{
// (x, y) represents chess board coordinates
// dist represent its minimum distance from the source
int x, y, dist;
// Node constructor
Node(int x, int y, int dist = 0): x(x), y(y), dist(dist) {}
// As we are using struct as a key in a std::set,
// we need to overload < operator
// Alternatively we can use std::pair<int, int> as a key
// to store coordinates of the matrix in the set
bool operator<(const Node& o) const
{
return x < o.x || (x == o.x && y < o.y);
}
};
// Find minimum number of steps taken by the knight
// from source to reach destination using BFS
int BFS(Node src, Node dest)
{
// set to check if matrix cell is visited before or not
set<Node> visited;
// create a queue and enqueue first node
queue<Node> q;
q.push(src);
// run till queue is not empty
while (!q.empty())
{
// pop front node from queue and process it
Node node = q.front();
q.pop();
int x = node.x;
int y = node.y;
int dist = node.dist;
// if destination is reached, return distance
if (x == dest.x && y == dest.y)
return dist;
// Skip if location is visited before
if (!visited.count(node))
{
// mark current node as visited
visited.insert(node);
// check for all 8 possible movements for a knight
// and enqueue each valid movement into the queue
for (int i = 0; i < 8; ++i)
{
// Get the new valid position of Knight from current
// position on chessboard and enqueue it in the
// queue with +1 distance
int x1 = x + row[i];
int y1 = y + col[i];
if (valid(x1, y1))
q.push({x1, y1, dist + 1});
}
}
}
// return INFINITY if path is not possible
return INT_MAX;
}
// main function
int main()
{
// source coordinates
Node src = {0, 7};
// destination coordinates
Node dest = {7, 0};
cout << "Minimum number of steps required is " << BFS(src, dest);
return 0;
}
According to the data you give, the two knights should move like this:
first knight: (0,0) -> (0,1)
second knight: (1,0) -> (1,1)
However, in your diagram, you imply that the knights should move like this (ignoring the wrong x-Axis that is missing the 1):
first knight: (0,0) -> (1,1)
second knight: (0,1) -> (1,0)
Your diagram moves each knight to the final position of the other knight, which is not correct. Your code gives 6, the correct solution to move each knight to its own final position as indicated by the data you give.
This is an answer assuming the ending positions are not linked to the knights (any knight can end up in any ending position). This is an algorithmic question independent of programming languages, so I won't show any code.
The simplest, but least efficient way would be to assume each knight has a single required final position. You assign all permutations of the final positions to the knights by index and for each permutation, calculate the result. Finally, you return the minimal result. In your example, one result would be 6 (original mapping), the other one would be 4 (swapped final positions, the only other permutation), so you'd get 4. The problem with this approach is that for n knights, you'll have n! permutations to consider.
The greedy approach would be for each knight to move until it hits one of the final spots, then for the other to hop to the other. This would work for your example but goes wrong for this one:
Knights: (5,4), (2,1); Final positions: (3,3), (9,6)
First knight would move
(5,4) -> (3,3)
and is done (1 step), second knight will then have to move
(2,1) -> (4,2) -> (5,4) -> (7,5) -> (9,6)
This needs 4 steps, making a total of 5. However, the optimal solution is:
(5,4) -> (7,5) -> (9,6)
(2,1) -> (3,3)
Which are 3 steps. So we see, a naive greedy algorithm does not necessarily yield a correct result.
However, we can do better with a greedy approach: First, calculate the distances between each knight/final position pair, and store them (using your original algorithm).
Our previous example would look like this:
(5,4) <- first knight
(3,3) = 1 <- distance to first final position
(9,6) = 2 <- distance to second final position
(2,1) <- second knight
(3,3) = 1
(9,6) = 4
Once you have calculated those, the algorithm will subsequently assign an ending position to the knights. It will work like this:
Loop over all knights that do not yet have an ending position. For each knight, mark the nearest final position and calculate the penalty on the other knights. The penalty is the maximum of additional moves for all other knights that have not yet been assigned. For example, selecting (3,3) for the knight at (5,4) would have a penalty of 3, since the other knight will now need to move 3 additional steps (as we marked its nearest final position). However, selecting (3,3) for the knight at (2,1) has a penalty of 1 because the other knight only needs to move one additional step.
After you calculated all penalties, assign the knight with the smallest penalty its nearest final position. Loop until all knights have been assigned a final position.
This algorithm is correct for both your original example and my example, however I don't know whether it's always correct. You'd need to prove that.

Belman-Ford algorithm in 2d Array

I've got a problem with applying a Bellman-Ford algorithm to 2D Array (not to graph)
Input array has m x n dimensions:
s[1,1] s[1,2] ... s[1,n] -> Exit
s[2,1] s[2,2] ... s[2,n]
...
Entry -> s[m,1] s[m,2] ... s[m,n]
And it is room-alike (each entry is a room with s[x,y] cost of enterance). Each room could have also a negative cost, and we have to find cheapest path from Entry to choosen room and to Exit.
For example, we've got this array of rooms and costs:
1 5 6
2 -3 4
5 2 -8
And we want to walk over room [3,2], s[3,2] = 4. We are starting form 5 at [1,3] and must walk over [3,2] before we go to [3,3].
And my question is, what is the best way to implement it in Bellman-Ford algorithm? I know that Dijkstry algorithm will not work becouse of negative cost.
Is for each room from [0, maxHeight] and relax all neighbors correct? Like this:
for (int i = height-1; i >= 0; --i) {
for (int j = 0; j < width; ++j) {
int x = i;
int y = j;
if (x > 0) // up
Relax(x, y, x - 1, y);
if (y + 1 < width) // right
Relax(x, y, x, y + 1);
if (y > 0) // left
Relax(x, y, x, y - 1);
if (x + 1 < height) // down
Relax(x, y, x + 1, y);
}
}
But how can I then read a cost to choosen room and from room to exit?
If you know how to move on the graph from an array, you can scroll to additional condition paragraph. Read also next paragraph.
In fact, you can look at that building like on a graph.
You can see like: (I forgot doors in second line, sorry.)
So, how it is possible to be implement. Ignore for the moment additional condition (visit a particular vertex before leaving).
Weight function:
Let S[][] be an array of entry cost. Notice, that about weight of edge decides only vertex on the end. It has no matter if it's (1, 2) -> (1,3) or (2,3) -> (1, 3). Cost is defined by second vertex. so function may look like:
cost_type cost(vertex v, vertex w) {
return S[w.y][w.x];
}
//As you can see, first argument is unnecessary.
Edges:
In fact you don't have to keep all edges in some array. You can calculate them in function every time you need.
The neighbours for vertex (x, y) are (x+1, y), (x-1, y), (x, y+1), (x, y-1), if that nodes exist. You have to check it, but it's easy. (Check if new_x > 0 && new_x < max_x.) It may look like that:
//Size of matrix is M x N
is_correct(vertex w) {
if(w.y < 1 || w.y > M || w.x < 1 || w.x > N) {
return INCORRECT;
}
return CORRECT;
}
Generating neighbours can look like:
std::tie(x, y) = std::make_tuple(v.x, v.y);
for(vertex w : {{x+1, y}, {x-1, y}, {x, y+1}, {x, y-1}}) {
if(is_correct(w) == CORRECT) {//CORRECT may be true
relax(v, w);
}
}
I believe, that it shouldn't take extra memory for four edges. If you don't know std::tie, look at cppreference. (Extra variables x, y take more memory, but I believe that it's more readable here. In your code it may not appear.)
Obviously you have to have other 2D array with distance and (if necessary) predecessor, but I think it's clear and I don't have to describe it.
Additional condition:
You want to know cost from enter to exit, but you have to visit some vertex compulsory. Easiest way to calculate it is to calculate cost from enter to compulsory and from compulsory to exit. (There will be two separate calculations.) It will not change big O time. After that you can just add results.
You just have to guarantee that it's impossible to visit exit before compulsory. It's easy, you can just erase outgoing edges from exit by adding extra line in is_correct function, (Then vertex v will be necessary.) or in generating neighbours code fragment.
Now you can implement it basing on wikipedia. You have graph.
Why you shouldn't listen?
Better way is to use Belman Ford Algorithm from other vertex. Notice, that if you know optimal path from A to B, you also know optimal path from B to A. Why? Always you have to pay for last vertex and you don't pay for first, so you can ignore costs of them. Rest is obvious.
Now, if you know that you want to know paths A->B and B->C, you can calculate B->A and B->C using one time BF from node B and reverse path B->A. It's over.
You just have to erase outgoing edges from entry and exit nodes.
However, if you need very fast algorithm, you have to optimize that. But it is for another topic, I think. Also, it looks like no one is interested in hard optimization.
I can quickly add, just that small and easy optimization bases at that, that you can ignore relaxation from correspondingly distant vertices. In array you can calculate distance in easy way, so it's pleasant optimization.
I have not mentioned well know optimization, cause I believe that all of them are in a random course of the web.

4 by 3 lock pattern

I came across this problem.
which asks to calculate the number of ways a lock pattern of a specific length can be made in 4x3 grid and follows the rules. there may be some of the points must not be included in the path
A valid pattern has the following properties:
A pattern can be represented using the sequence of points which it's touching for the first time (in the same order of drawing the pattern), a pattern going from (1,1) to (2,2) is not the same as a pattern going from (2,2) to (1,1).
For every two consecutive points A and B in the pattern representation, if the line segment connecting A and B passes through some other points, these points must be in the sequence also and comes before A and B, otherwise the pattern will be invalid. For example a pattern representation which starts with (3,1) then (1,3) is invalid because the segment passes through (2,2) which didn't appear in the pattern representation before (3,1), and the correct representation for this pattern is (3,1) (2,2) (1,3). But the pattern (2,2) (3,2) (3,1) (1,3) is valid because (2,2) appeared before (3,1).
In the pattern representation we don't mention the same point more than once, even if the pattern will touch this point again through another valid segment, and each segment in the pattern must be going from a point to another point which the pattern didn't touch before and it might go through some points which already appeared in the pattern.
The length of a pattern is the sum of the Manhattan distances between every two consecutive points in the pattern representation. The Manhattan distance between two points (X1, Y1) and (X2, Y2) is |X1 - X2| + |Y1 - Y2| (where |X| means the absolute value of X).
A pattern must touch at least two points
my approach was a brute force, loop over the points, start at the point and using recursive decremente the length until reach a length zero then add 1 to the number of combinations.
Is there a way to calculate it in mathematical equation or there is a better algorithm for this ?
UPDATE:
here is what I have done, it gives some wrong answers ! I think the problem is in isOk function !
notAllowed is a global bit mask of the not allowed points.
bool isOk(int i, int j, int di,int dj, ll visited){
int mini = (i<di)?i:di;
int minj = (j<dj)?j:dj;
if(abs(i-di) == 2 && abs(j-dj) == 2 && !getbit(visited, mini+1, minj+1) )
return false;
if(di == i && abs(j - dj) == 2 && !getbit(visited, i,minj+1) )
return false;
if(di == i && abs(j-dj) == 3 && (!getbit(visited, i,1) || !getbit(visited, i,2)) )
return false;
if(dj == j && abs(i - di) == 2 && !getbit(visited, 1,j) )
return false;
return true;
}
int f(int i, int j, ll visited, int l){
if(l > L) return 0;
short& res = dp[i][j][visited][l];
if(res != -1) return res;
res = 0;
if(l == L) return ++res;
for(int di=0 ; di<gN ; ++di){
for(int dj=0 ; dj<gM ; ++dj){
if( getbit(notAllowed, di, dj) || getbit(visited, di, dj) || !isOk(i,j, di,dj, visited) )
continue;
res += f(di, dj, setbit(visited, di, dj), l+dist(i,j , di,dj));
}
}
return res;
}
My answer to another question can be adapted to this problem as well.
Let f(i,j,visited,k) the number of ways to complete a partial pattern, when we are currently at node (i,j), have already visited the vertices in the set visited and have so far walked a path length of k. We can represent visited as a bitmask.
We can compute f(i,j,visited,k) recursively by trying all possible next moves and apply DP to reuse subproblem solutions:
f(i,j, visited, L) = 1
f(i,j, visited, k) = 0 if k > L
f(i,j, visited, k) = sum(possible moves (i', j'): f(i', j', visited UNION {(i',j')}, k + dis((i,j), (i',j')))
Possible moves are those that cross a number of visited vertices and then end in an univisited (and not forbidden) one.
If D is the set of forbidden vertices, the answer to the question is
sum((i,j) not in D: f(i,j, {(i,j)}, L)).
The runtime is something like O(X^2 * Y^2 * 2^(X*Y) * maximum possible length). I guess the maximum possible length is in fact well below 1000.
UPDATE: I implemented this solution and it got accepted. I enumerated the possible moves in the following way: Assume we are at point (i,j) and have already visited the set of vertices visited. Enumerate all distinct coprime pairs (dx,dy) 0 <= dx < X and 0 <= dy < Y. Then find the smallest k with P_k = (i + kdx, j + kdy) still being a valid grid point and P_k not in visited. If P_k is not forbidden, it is a valid move.
The maximum possible path length is 39.
I'm using a DP array of size 3 * 4 * 2^12 * 40 to store the subproblem results.
There are a couple of attributes of the combinations that may be used to optimize the brute force method:
Using mirror images (horizontal, vertical, or both) you can generate 4 combinations for each one found (except horizontal or vertical lines). Maybe you could consider only combinations starting in one quadrant.
You can usually generate additional combinations of the same length by translation (moving a combination).

Determining if a set of points are inside or outside a square

I have two of these:
bool isPointOnShape(int a, int b)
{
}
bool isPointInShape(int a, int b)
{
}
Say I have a square, first point (bottom left corner) is x,y (0,0) second point (top left) is (0,2), third is (2,2) and fourth is (0,2).
The Points on shape would be (0,1) (1,2) (2,1) (1,0) and Points in shape is (1,1)
How do I find out the points on shape / in shape and return a true value so that I can store it somewhere?
I'll offer a general solution for any shape that can be divided in straight segments.
So, as you may have guessed, I'll start by consider your "shape" as a list of segments that completes a loop. Or simply put a circular list of points that represents a loop, for example, your square would be this list of points:
0, 0
0, 2
2, 2
2, 0
Note that we consider that there are segments from each point to the next and that the final point connects to the first. Also, we require that no consecutive points are equal, nor the first and last. If there are any, those must be removed before proceeding.
Now, for each segment we can determinate the bounding box. For example given this segment:
a = (0, 2)
b = (2, 2)
Then the range of values in x is [0, 2] and in y is [2, 2] and that is your bounding box for that segment.
The next thing you need is the director vector of the line of the segment. To get that, first calculate the length of the segment:
length = sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y))
And then:
director.x = (a.x - b.x)/length
director.y = (a.y - b.y)/length
Note 1: when then length is 0, then you have an invalid segment. That's why we don't want repeated points.
Note 2: Using the director vector instead of using the equation of the line will make things easier.
Now, given a point p, you can determinate if that point is in a segment (if it is one of the points in the list). For the rest of cases we start by looking if it is inside of the axis aligned bounding box. This is done simply by checking the range:
if
(
(p.x >= box.left && p.x <= box.right) &&
(p.y >= box.top && p.y <= box.bottom) // with origin at the top-left corner
)
{
//It is inside of the bounding box
}
And if it is, then we calculate the distance from the point to the line, if it is
0 then it is on the line. Now, because of floating point arithmetics, you could test if the distance is less or equal to epsilon, where epsilon is a very small number.
We use this formula:
distance vector = (a - p) - ((a - p) · director) * director
distance = the norm of distance vector
Where "·" denotes a dot product and "*" denotes an scalar product.
All that rests is to iterate over the segments, for each one calculate the distance and if for anyone the distance is less than epsilon then the point is "on the shape".
Ok, but what about "in the shape"?
Well, with a little help of a trick from topology we can determinate if a point is inside or not. This is the same algorithm Windows would use to fill a polygon or polyline (such as deciding what is inside a selected area with free hand in Microsoft Paint).
It goes like this:
Count the number of segments you have to cross to get to the point from outside. If the number is pair, then it is outside, if it is odd then inside.
You can choose from what direction to reach the point. I choose left.
Once more, you are going to iterate over the segments. For each one we need to decide if it is at the vertical range. For that use the bounding box:
if ((p.y >= box.top && p.y <= box.bottom))
{
//In the vertical range
}
Now, determinate if the segment is at left, or right:
if (p.x < box.left)
{
//The segment is at the left
}
else if (p.x > box.right)
{
//The segment is at the right
}
else
{
//The segment is close, need further calculation
}
In the case that the segment is close we need to calculate the vector distance to that segment and check it's direction.
The vector distance? Well, we already have it, we are taking its norm to determinate the distance. Now, instead of taking the norm, verify the sign of the x coordinate. If it is less than 0, it is right, if it is more than 0 then it is left. If it is 0... it means that the segment is horizontal (because the distance vector is always perpendicular to the segment), you can skip that segment*.
*: In fact, if the segment is horizontal and it is in vertical range, it means that it is at the segment. Are segments "in shape" or not?
Now, you need to count the number of segments at the left, and if it odd, the point is inside the shape. It is out otherwise. This can also be done with the segments that are up, or right, or below. I just picked left.
For large shapes where iterating over all the segments is expensive, you can store the segments in some space partitioning data structure. That is beyond the scope of this post.
If I suppose you have a Rectangle class and that this class has members bottomLeft and topRight, you can write something like this:
bool Rectangle::isPointOnShape(int x, int y) {
if (x == bottomLeft.x || x == topRight.x)
if (y > bottomLeft.y && y < topRight.y)
return true;
if (y == bottomLeft.y || y == topRight.y)
if (x > bottomLeft.x && x < topRight.x)
return true;
}
bool Rectangle::isPointInShape(int x, int y) {
bool inX = false;
bool inY = false;
if (x > bottomLeft.x && x < topRight.x)
inX = true;
if (y > bottomLeft.y && y < topRight.y)
inY = true;
return (inX && inY);
}
If your shape is not a rectangle, this functions will be different of course.

topology layers separation algorithm

I have the following problem. Suppose you have a big array of Manhattan polygons on the plane (their sides are parallel to x or y axis). I need to find a polygons, placed closer than some value delta. The question - is how to make this in most effective way, because the number of this polygons is very large. I will be glad if you will give me a reference to implemented solution, which will be easy to adapt for my case.
The first thing that comes to mind is the sweep and prune algorithm (also known as sort and sweep).
Basically, you first find out the 'bounds' of each shape along each axis. For the x axis, these would be leftmost and rightmost points on a shape. For the y axis, the topmost and bottommost.
Lets say you have a bound structure that looks something like this:
struct Bound
{
float value; // The value of the bound, ie, the x or y coordinate.
bool isLower; // True for a lower bound (leftmost point or bottommost point).
int shapeIndex; // The index (into your array of shapes) of the shape this bound is on.
};
Create two arrays of these Bounds, one for the x axis and one for the y.
Bound xBounds* = new Bound[2 * numberOfShapes];
Bound yBounds* = new Bound[2 * numberOfShapes];
You will also need two more arrays. An array that tracks on how many axes each pair of shapes is close to one another, and an array of candidate pairs.
int closeAxes* = new int[numberOfShapes * numberOfShapes];
for (int i = 0; i < numberOfShapes * numberOfShapes; i++)
CloseAxes[i] = 0;
struct Pair
{
int shapeIndexA;
int shapeIndexB;
};
Pair candidatePairs* = new Pair[numberOfShapes * numberOfShape];
int numberOfPairs = 0;
Iterate through your list of shapes and fill the arrays appropriately, with one caveat:
Since you're checking for closeness rather than intersection, add delta to each upper bound.
Then sort each array by value, using whichever algorithm you like.
Next, do the following (and repeat for the Y axis):
for (int i = 0; i + 1 < 2 * numberOfShapes; i++)
{
if (xBounds[i].isLower && xBounds[i + 1].isLower)
{
unsigned int L = xBounds[i].shapeIndex;
unsigned int R = xBounds[i + 1].shapeIndex;
closeAxes[L + R * numberOfShapes]++;
closeAxes[R + L * numberOfShapes]++;
if (closeAxes[L + R * numberOfShapes] == 2 ||
closeAxes[R + L * numberOfShapes] == 2)
{
candidatePairs[numberOfPairs].shapeIndexA = L;
candidatePairs[numberOfPairs].shapeIndexB = R;
numberOfPairs++;
}
}
}
All the candidate pairs are less than delta apart on each axis. Now simply check each candidate pair to make sure they're actually less than delta apart. I won't go into exactly how to do that at the moment because, well, I haven't actually thought about it, but hopefully my answer will at least get you started. I suppose you could just check each pair of line segments and find the shortest x or y distance, but I'm sure there's a more efficient way to go about the 'narrow phase' step.
Obviously, the actual implementation of this algorithm can be a lot more sophisticated. My goal was to make the explanation clear and brief rather than elegant. Depending on the layout of your shapes and the sorting algorithm you use, a single run of this is approximately between O(n) and O(n log n) in terms of efficiency, as opposed to O(n^2) to check every pair of shapes.