Related
I'm working on a program in which I need to find all lines which are in a circles located at some cartesian point of some radius.
At the moment, for every circle, I am iterating over all the lines and checking if the line enters/contacts the circle at any point.
The code essentially looks like this.
for (int i = 0; i < num_circles; i++)
{
for (int j = 0; j < num_lines; j++)
{
if(lineIntersectWithCircle(circle[i], lines[j]))
{
//Append line[j] to a list of lines intersecting with circle[i];
//some code
}
}
}
I've been thinking of many way to optimize this, but I'm having trouble.
I have sorted the circles by minimum Cartesian distance and sorted lines by maximum distance away. This way you can somewhat optimize, but it's quite minimal because once you reach the point where line[j].max > circle[i].min, you still have to iterate through all the rest of the lines.
I am fine with my intersection checking method, I just would like to minimize the amount of times I need to call it.
Is there a good way of doing this?
Cheapest way is just check the bounding extents/rectangles of the two shapes (line and circle) prior to the more expensive intersection test. Chances are that you can even compute the extents on the fly of the line/circle, not precompute, and still get a decent performance boost unless your line/circle intersection is already dirt cheap.
A really effective approach but one that requires a bit more work is to just create a grid. You can use the bounding rectangles computed above to cheaply see which grid cells your shapes intersect.
struct GridNode
{
// Points to the index of the next node in the grid cell
// or -1 if we're at the end of the singly-linked list.
int next_node;
// Points to the index of the shape being stored.
int shape;
};
struct GridCell
{
// Points to the first node or -1 if the cell is empty.
int first_node;
};
struct Grid
{
// Stores the cells in the grid. This is just illustrative
// code. You should dynamically allocate this with adjustable
// grid widths and heights based on your needs.
struct GridCell cells[grid_width * grid_height];
// Stores the nodes in the grid (one or more nodes per shape
// inserted depending on how many it intersects). This is
// a variable-sized array you can realloc needed (ex: double
// the size when you're out of room).
struct GridNode* nodes;
// The maximum number of nodes we can store before realloc.
int node_cap;
// The number of nodes inserted so far. realloc when this
// exceeds node_cap.
int node_num;
};
... something to this effect. This way, most of the time you can insert elements to the grid doing nothing more than just some integer (emulating pointers) operations and adding some grid node entries to this variable-sized nodes array. Heap allocations occur very infrequently.
I find in practice this outperforms quad-trees if you have many dynamic elements moving from one cell to the next like in a 2D video game where everything is moving around all the time while we need rapid collision detection, and can even rival quad-trees for searching if you are careful with the memory layout of the nodes to minimize cache misses when iterating through grid cells that intersect the shape you are testing against. You can even do a post-pass after the grid is constructed to rearrange the memory of each node for cache-friendly list iteration based on how efficient you need the intersection searches to be. If you want to get fancy, you can use Bresenham to figure out exactly what grid cells a line intersects, e.g., but given the quadratic complexity of what you're doing, you stand to improve exponentially without bothering with that and just doing it in a very simple way with bounding rectangles.
Basically to find an intersection, first grab the bounding rect of the shape. Then see which cells it intersects in the grid. Now check for intersection with the shapes contained in the grid cells the original shape intersects. This way you can work towards constant-time complexity except for gigantic shapes (worst-case with O(n)) which are hopefully a rare case.
I even find use for these in 3 dimensions when things are moving around a lot. They're often cheaper than the octree, BVH, and kd-tree variants which provide extensive search acceleration but at the cost of more expensive builds and updates, and if you use this strategy of a singly-linked list for each grid cell which doesn't have to individually allocate nodes, you can store it in a very reasonable amount of memory even with the 3rd dimension. I wouldn't use a 3-dimensional version of this for raytracing, but it can be very useful for 3D collision detection, like detecting collision between particles moving every single frame.
As with anything it depends on your use case. If you have a fixed number of lines or infrequently added, you may want to precompute some of the calculations needed to find out if any part of the line is within radius distance of the center of the circle
Starting with the equation for the shortest distance between a line and a point and comparing that distance is less than the radius of the circle:
//abs(Cx*(y1-y0)-Cy*(x1-x0)+x1*y0-y1*x0)/sqrt((y1-y0)*(y1-y0)+(x1-x0)*(x1-x0))<R
//pull out some constants and cache these as they are initialized
//int y10 = y1-y0, //add to the line struct
// x10 = x1 -x0,
// delta = x1*y0-y1*x0,
// sides = (y10)*(y10)+(x10)*(x10);
// R2 = R*R; //add to the circle struct
//now the equation factors down to
//abs(Cx*(y10)-Cy*(x10)+delta)/sqrt(sides)< R //replace constants
//abs(Cx*(y10)-Cy*(x10)+delta) < sqrt(sides) * R //remove division
//pow(Cx*(y10)-Cy*(x10)+delta , 2.0) < sides * R * R //remove sqrt()
//int tmp = Cx*(y10)-Cy*(x10)+delta //factor out pow data
//tmp * tmp < sides * R2 //remove pow() and use cache R squared
//now it is just a few cheap instructions
Now the check should be just 4 integer multiplies, 2 add/subtract and a compare.
lineIntersectWithCircle(size_t circle, size_t line){
struct circle C = circle_cache[circle]; //these may be separate arrays
struct line L = line_cache[line]; //from your point data
long tmp = C.x * L.y10 - C.y * L.x10 + L.delta;
return (tmp*tmp < L.sides * C.R2);
}
... but you may want to check my math - its been a while. Also I assumed the points would be integers - change to float as needed - it should still be relatively fast.
If that isn't fast enough you can add additional data for the bounding boxes of the circle and line
bool lineIntersectWithCircle(size_t circle, size_t line){
struct circle C = circle_cache[circle]; //these may be separate arrays
struct line L = line_cache[line]; //from your point data
//if the bounding boxes don't intersect neither does the line
//this may not be _that_ helpful and you would need to:
// figure out the bounding boxes for each line/circle
// and cache additional data
if (C.leftx > L.rightx || L.leftx > C.rightx) //a box is to the side
return 0;
if (C.topy < L.boty || L.topy < C.boty) //a box is below/above
return 0;
//the bounding boxes intersected so check exact calculation
long tmp = C.x * L.y10 - C.y * L.x10 + L.delta;
return (tmp*tmp < L.sides * C.R2);
}
I have a simple game project i'm working on to learn/improve my C knowledge. At the moment i have an array that contains a 'map' of my terrain, it also contains items and enemies. This is working fine, but to improve it, i'm trying to have two arrays that overlap, so i never put item's on the terrain, but in a separate item array which overlaps the terrain.
I've approached it in the way below;
void items(int * terrainMap, int itemCount, int * itemMap){
int newx = getRand(0, xsize);
int newy = getRand(0, ysize);
int count = 0;
while (count < itemCount){
if (getCell(newx, newy, terrainMap) == corridoor|| getCell(newx, newy, terrainMap) == floor){
setCell(newx, newy, chest, itemMap);
count++;
}
else {
newx = getRand(0, xsize);
newy = getRand(0, ysize);
}
}
}
Both arrays are initialized, terrain is mapped out, items is set to empty tiles. What i'm trying to do is in the if conditions, check if the terrain is passable (corridor or floor) and if so, place a chest- but place it in the item array, not on the terrain. The above code work if i place a chest on terrain, but only ever seems to place one chest in the item array.
Can someone please over me some assistance as to where i'm going wrong? Or suggest some improvements to this method? Thanks very much in advance - i'm very new to C and coding so any advice is great.
You don't modify newx and newy after adding the chest (you aren't hitting the else), so you end up adding the chest to the same position itemCount times.
You can fix this by moving your assignment of newx and newy outside of the else (to update them every time you enter the loop). You might also want to check if there isn't already a chest at that position to guarantee you get that many chests.
I have two arrays, each containing a different ordering of the same set of integers. Each integer is a label for a point in which two closed paths intersect in the plane. The two arrays are interpreted as giving the circular ordering (in clockwise order) of points along each of two closed paths in the plane, with no particular starting point. The two paths intersect with each other as many times as there are points in the arrays, but a path may not self-intersect at all. How do I determine, from these two arrays, whether it is possible to draw the two paths in the plane without self-crossings? (The integer labels have no inherent meaning.)
Example 1: A = {3,4,2,1,10,7} and B = {1,2,4,10,7,3}: it is possible
Example 2: A = {2,3,0,10,8,11} and B = {10,2,3,8,11,0}: it is not possible.
Try it by drawing a circle, with 6 points labelled around it according to A, then attempt to connect the 6 points in a second closed path, according to the ordering in B, without crossing the new line you are drawing. (I believe it makes no difference to the possibility/impossibility of drawing the line whether you start by exiting or entering the first loop.) You will be able to do it for example 1, but not for example 2.
I am currently using a very elaborate method where I look at adjacent pairs in one array, e.g. in Example 1, array A is divided into {3,4}, {2,1}, {10,7}, then I find the groupings in the array B as partitioned by the two members listed in each case:
{3,4} --> {{1,2}, {10,7}}
{2,1} --> {{4,10,7,3}, {}}
{10,7} --> {{3,1,2,4}, {}}
and check that each pair on the left-hand-side finds itself in the same grouping of the right-hand-side partition in each of the other 2 rows. Then I do the same, offset by one position:
{4,2} --> {{10,7,3,1}, {}}
{1,10} --> {{2,4}, {7,3}}
{7,3} --> {{1,2,4,10}, {}}
Everything checks out here.
In Example 2, though, the method shows that it is impossible to draw the path. Among the "offset by 1" pairs from array A we find {10,8} causes a partition of array B into {{2,3}, {11,0}}. But we need 11 and 2 to be in the same grouping, as they are the next pair of points in array A.
This idea is unwieldy, and my implementation is even more unwieldy. I'm not even 100% convinced it always works. Could anyone suggest an algorithm for deciding? Target language is C, if that matters.
EDIT: I've added an illustration here: http://imgur.com/TS8xDIk. Here the paths to be reconciled share points 0, 1, 2 and 3. On the black path they are visited in order (A = {0,1,2,3}). On the blue path we have B = {0,2,1,3}. You can see on the left-hand side that this is impossible--the blue path will have to self-intersect in order to do it (or have additional intersections with the black path, which is also not allowed).
On the right-hand side is an illustration of the same problem interpreted as a graph with edges, responding to the suggestion that the problem boils down to a check for planarity. Well, as you can see, it's quite possible to form a planar graph from this collection of edges, but we cannot read the graph as two closed paths with n intersections--the blue path has "intersections" with the other path that don't actually cross. The paths are required to cross from inside to outside or vice-versa at each node, they cannot simply kiss and turn back.
I hope this clarifies the problem and I apologise for any lack of clarity the first time around.
By the way introducing coordinates would be a complete red herring: any point can be given any coordinates, and the problem remains the same. In a sense it is topological more than geometrical. Thanks for any additional suggestions on how to accomplish this feasibility check.
SECOND EDIT to show my current code. Like in the suggestion below by svinja, I first reduced the two arrays to a permutation of 0..2n-1. The input to the function is two arrays (which contain different orderings of the same 2n integers) and the length of these arrays. I am a hobbyist with no training in programming so I expect you will find several infelicities in the approach to coding. The idea is to return 1 if the arrays A and B are in a permutational relationship that allows the path to be drawn, and 0 if not.
int isGoodPerm(int A[], int B[], int len)
{
int i,j,a,b;
int P[max_len];
for (i=0; i<len; i++)
for (j=0; j<len; j++)
if (B[j] == A[i])
{
P[i] = j;
break;
}
for (i=0; i<len; i++)
{
if (P[i] < P[(i+1)%len])
{
a = P[i];
b = P[(i+1)%len];
}
else
{
a = P[(i+1)%len];
b = P[i];
}
for (j=i+2; j<i+len; j+=2)
if ((P[j%len] > a && P[j%len] < b) != (P[(j+1)%len] > a && P[(j+1)%len] < b))
return 0;
}
return 1;
}
I'm actually still testing another part of this project, and have only tested this part in isolation. I tweaked a couple of things when pasting it into the larger codebase and have copied that version--I hope I didn't introduce any errors.
I think the long question is hiding the true intent. I might be missing something, but it looks like the only thing you really need to check is if the points in an array can be drawn without self-intersecting. I'm assuming you can map the integers to the actual coordinates. If so, you might find the solution posed by the related math.statckexchange site here describing either the determinant-based method or the Bentley-Ottman algorithm for crossings to be helpful.
I am not sure if this is correct, but as nobody is posting an answer, here it is:
We can convert any instance of this problem to one where the first path is (0, 1, 2, ... N). In your example 2, this would be (0, 1, 2, 3, 4, 5) and (3, 0, 1, 4, 5, 2). I only mention this because I do this conversion in my code to simplify further code.
Now, imagine the first path are points on a circle. I think we can assume this without loss of generality. I also assume we can start the second path either inside or outside of the circle, if one works the other should, too. If I am wrong about either, the algorithm is certainly wrong.
So we always start by connecting the first and second point of the second path on the, let's say, outside. If we connect 2 points X and Y which are not right next to each other on the circle, we divide the remaining points into group A - the ones from X to Y clockwise, and group B - the ones from Y to X clockwise. Now we remember that points from group A can no longer be connected to points from group B on the outside part.
After this, we continue connecting the second and third point of the second path, but we are now on the inside. So we check "can we connect X and Y on the inside?" if we can't, we return false. If we can, we again find groups A and B and remember that none of them can be connected to each other, but now on the inside.
Now we're back on the outside, and we connect the third and fourth point of the second path... And so on.
Here is an image that shows how it works, for your examples 1 and 2:
And here is the code (in C#, but should be easy to translate):
static bool Check(List<int> path1, List<int> path2)
{
// Translate into a problem where the first path is (0, 1, 2, ... N}
var path = new List<int>();
foreach (var path2Element in path2)
path.Add(path1.IndexOf(path2Element));
var N = path.Count;
var blocked = new bool[N, N, 2];
var subspace = 0;
var currentElementIndex = 0;
var nextElementIndex = 1;
for (int step = 1; step <= N; step++)
{
var currentElement = path[currentElementIndex];
var nextElement = path[nextElementIndex];
// If we're blocked before finishing, return false
if (blocked[currentElement, nextElement, subspace])
return false;
// Mark appropriate pairs as blocked
for (int i = (currentElement + 1) % N; i != nextElement; i = (i + 1) % N)
for (int j = (nextElement + 1) % N; j != currentElement; j = (j + 1) % N)
blocked[i, j, subspace] = blocked[j, i, subspace] = true;
// Move to the next edge
currentElementIndex = (currentElementIndex + 1) % N;
nextElementIndex = (nextElementIndex + 1) % N;
// Outside -> Inside, or Inside -> Outside
subspace = (2 - subspace) / 2;
}
return true;
}
Old answer:
I am not sure I understood this problem correctly, but if I have, I think this can be reduced to planarity testing. I will use your example 2 for the numbers:
Create graph G1 from the first array; it has edges 2-3, 3-0, 10-8, 8-11, 11-2
Create graph G2 from the second array; 10-2, 2-3, 3-8, 8-11, 11-0, 0-10
Create graph G whose set of edges is the union of the sets of edges of G1 and G2: 2-3, 3-0, 10-8, 8-11, 11-2, 10-2, 3-8, 11-0, 0-10
Check if G is planar.
This is if I correctly interpreted the question in the sense that the second path must not cross itself but must not cross the first path either (except for the unavoidable 1 intersection per vertex due to shared vertices). If this is not the case, then Example 2 does have solutions (note how the 11-2 and 8-10 edges are crossed by the second path).
I have been trying to write an FPS in C/X11/OpenGL, but the issue that I have encountered is with calculating where the bullet hits. I have used a horrible technique, and it only sometimes works:
pos size, p;
size.x = 0.1;
size.z = 0.1; // Since the game is technically top-down (but in a 3D perspective)
// Positions are in X/Z, no Y
float f; // Counter
float d = FIRE_MAX + 1 /* Shortest Distance */, d1 /* Distance being calculated */;
x = 0; // Index of object to hit
for (f = 0.0; f < FIRE_MAX; f += .01) {
// Go forwards
p.x = player->pos.x + f * sin(toRadians(player->rot.x));
p.z = player->pos.z - f * cos(toRadians(player->rot.x));
// Get all objects that collide with the current position of the bullet
short* objs = _colDetectGetObjects(p, size, objects);
for (i = 0; i < MAX_OBJECTS; i++) {
if (objs[i] == -1) {
continue;
}
// Check the distance between the object and the player
d1 = sqrt(
pow((objects[i].pos.x - player->pos.x), 2)
+ pow((objects[i].pos.z - player->pos.z),
2));
// If it's closer, set it as the object to hit
if (d1 < d) {
x = i;
d = d1;
}
}
// If there was an object, hit it
if (x > 0) {
hit(&objects[x], FIRE_DAMAGE, explosions, currtime);
break;
}
}
It just works by making a for-loop and calculating any objects that might collide with where the bullet currently is. This, of course, is very slow, and sometimes doesn't even work.
What would be the preferred way to calculate where the bullet hits? I have thought of making a line and seeing if any objects collide with that line, but I have no idea how to do that kind of collision detection.
EDIT: I guess my question is this: How do I calculate the nearest object colliding in a line (that might not be a straight 45/90 degree angle)? Or are there any simpler methods of calculating where the bullet hits? The bullet is sort of like a laser, in the sense that gravity does not affect it (writing an old-school game, so I don't want it to be too realistic)
For every object you want to be hit-able, define a bounding object.
Simple examples would be a sphere or a box.
Then you have to implement a ray-sphere or ray-box intersection.
For exaple have a look at line-sphere intersection.
For boxes, you can either test aginast the four bounding lines, but there are algorithms optimsed for axis aligned boxes.
With this, proceed as you already do. For every object in the scene, check for intersection, if intersects, compare distance to previous intersected objects, take the one that is hit first.
The intersection algorithems give you the ray parameter as a result (the value t for which hit_position = ray_origin + t * ray_direction) which you can use to compare the distances.
You can organise all scene objects in the BSP tree then hit\collide detection will be pretty easy to implement. Also you can use BSP to detect invisible objects and discard them before rendering.
Basically I've got some structs of type Ship which are going to go on a board which can have a variable width and height. The information about the ships is read in from a file, and I just need to know the best way to make sure that none of the ships overlap.
Here is the structure of Ship:
int x // x position of first part of ship
int y // y position of first part of ship
char dir // direction of the ship, either 'N','S','E' or 'W'
int length // length of the ship
Also, what would be a good way to handle the directions. Something cleaner than using a switch statement and using a different condition for each direction.
Any help would be greatly appreciated!
You could keep a boolean array of the entire grid, initially initialized to "false." For each ship, for each location the ship covers, check if the location is "false." If it is,
set it to "true". If not, then some other ship is on the location.
This algorithm is linear in the total area of all the ships, but also requires extra space
proportional to the number of locations on the board.
This is the same thing as a test whether rectangles intersect, I think your code would be simpler if you don't think of these ships as a point,length, and direction but as a rectangle.
So convert this
int x // x position of first part of ship
int y // y position of first part of ship
char dir // direction of the ship, either 'N','S','E' or 'W'
int length // length of the ship
to this (allow negative cx & cy to get N,S,E,W)
int x // x position of first part of ship
int y // y position of first part of ship
int cx // length of the ship in X
int cy // length of the ship in Y
or this
int left // x position of Eastern part of the ship
int top // y position of Northernmost part of ship
int right // x position of Westernmost part of the ship
int bottom // y position of Southernmost part of ship
bool orientation; // so we can tell East from West or North from South.
Then a simple function can determine if two ships intersect.
bool DoShipsIntersect(Ship * a, Ship * b)
{
if ((a->right < b->left) || (b->right < a->left))
return false;
if ((a->bottom < b->top) || (b->bottom < a->top))
return false;
return true;
}
A brute force compare of every ship to every other ship should be quite fast as long as you don't have thousands of ships.
Unless you have a lot of ships then just use a simple brute force algorithm, which will be two nested loops, i.e. O(n^2).
Keep a bitmap of the board where each bit indicates whether there's a ship occupying that tile. For each ship mark the tiles it occupies on the board, and check out if you mark the same bit twice.
(Battleship?)
Make a 2D array ("board") which contains the ID of the ship when one is present. Therefore, when you add the ship you can check in O(length) time whether a space is occupied or not.
O(n * length) time, O(N^2) space.
One way of representing a direction is as a unit vector. This can be 2 integers: dirX and dirY. Eg. dirX=1 for East; or dirY=1 for South.
You can then iterate over all positions occupied by a ship with:
int cx = x;
int cy = y;
for(int i = 0; i < length; i++) {
cx += dirX;
cy += dirY;
}
Or get a bounding-box based on these values:
x
y
x + dirX * (length - 1)
y + dirY * (length - 1)
You might want to use an enum type for your direction. In terms of finding overlaps, create a two dimensional array of booleans initialized to false for your board. Then, for each ship, finding the corresponding entries in the array and, if they are already true, you have an overlap. Otherwise, set those entries to true. If you have placed all your ships and didn't encounter an already true entry, then there is no overlap.