So I have a bounded plane (X axis range 0-1000, Y axis range 0-2000).
there are multiple points (x,y) in it, and a rectangle (4 points that makes the rectangle). Some points are in the rectangle and some aren't. like this:
The rectangle is able to move and change it's size over time. while the points are static and won't change. I need to check what points are inside the rectangle after it changes.
Problem:
Giving a rectangle, what points are inside of it?
Set<Point> getPointsInsideRectangle(Rectangle rec);
My naive solution:
for each point
check if it inside the rectangle, if yes, add the point to a Point Set
return the Point Set
My thoughts:
It seems that iterating over all the points everytime the rectangle changes seems extremely not efficient with big CPU usage (there are many points). Something tells me to use HashMap but since the rectangle is a X range and a Y range (and not just 1 value), it seems I cannot use it.
My questions:
1. Is there a java data structure that can handle this situation?
2. if not, any thoughts on how to implement a data structure that holds all the points, and giving a rectangle, returns the points in it?
Just some random thoughts:
May try to create some kind of container for a specific range, like x from 0 to 100 and y from 0 to 100 l and repeat that with more containers like x from 100 to 200 and y from 0 to 100 etc and add your points to where they belong to.
Something like
Class Container
{
Int minX;
Int maxX
Int minY;
Int maxY;
List<Point> points;
Check(int x, int y)
(
return x >= minX && x <= maxX && y >= minY && y <= maxY;
)
}
Let's call the 4 points of the rectangle A (upper left), B (upper right), C (bottom right) and D (bottom left).
Start to check all containers with A.X and A.Y and then add the default range of a container to A.X and check again all containers that are not already in your bounds. Repeat till there's less than the default range left to B.X and then add what's left.
Same from A.X and A.Y to D.X and D.Y with Y decreased by the default container range and so on and so on.. .
Maybe even create containers containing containers to scale down the amount of comparissions even more.
This way you can check for containers which overlap with your rectangle and compare the points which are in these containers.
May even use multithreading to check the containers.
(Sorry for bad editing, I'm on my phone)
Edit
Now that I reread that, I think this could results in a kind of tree structure
update
A tree seems like the right thing to go for here: Range Tree (Wikipedia)
Example implementation: Java Range tree example ( by Robert Sedgewick and Kevin Wayne. )
K-d tree (2d case) could be the starting point. It's rather simple to implement and fast enough.
Sample visualization:
Some links to java implementations: KDTree Implementation in Java
As other mentioned already, there are many data structures for spatial index:
Quadtrees
R-Trees (an R*Tree is an improved R-Tree)
KD-Trees
You have to perform a window query (sometimes called rectangle query or range query) on the index, where the query rectangle would be exactly your moving rectangle.
If you are looking for various implementations of such spatial data structures, have a look here (R*Tree, quadtrees, STR-loaded R-Tree), Or have a look at the PH-Tree, it is similar to a quadtree but much more efficient and inherently limited depth.
Related
I'm trying to make a game and I need the player(rectangle) to always be looking at the mouse, I have found some pages on this but I can't seem to understand the math.
Main:
g2d.rotate(calculateRotation, x,y);
g2d.fill(player);
g2d.rotate(-calculateRotation, x,y);
Mouse Listener:
int mx = e.getX();
int mY = e.getY();
float rotation = Math.atan((mouseX-playerX)/(mouseY-playerY)); //<--- I don't know
would it be something like this?
You should use linear algebra- instead of using sines and cosines, you use vectors.
If you have P1=(x1,y1) (where the player is) and P2=(x2,y2) (where the mouse pointer is), then you have the vector V=(x2-x1,y2-y1)=(v1,v2), which has length v=|V|=sqrt(v1^2+v2^2). Then you have the versor (which is a vector of length=1) M=(v1/v,v2/v)=(m1,m2).
Then instead of computing an angle, you can rotate points by mapping (x,y)->(x* m1-y* m2, x* m2+y*m1).
See also https://en.wikipedia.org/wiki/Rotation_matrix#In_two_dimensions
(and remember to take care in the case V=0)
Note: using atan is OK, but you will need to check the signs of x and y.. If they are both negative you'll find the wrong angle; and if one is positive and the other is negative, you still don't know if your arrow points NW or SE.
So I have a fairly large array that contains xyz coordinates, where array[0] = x0, array[1] = y0, array[2] = z0, array[3] = x1, array[4] = y1... and so on.
I'm running an algorithm on this array that is taking longer than I would like it to, and I want to split the work amongst threads. I have my threads set up, but I am not sure how to divide this array properly so I can distribute this work across 3 threads.
Even though I have an array length that is divisible by 3, this won't work, because splitting into 3 can split an xyz coordinate (for instance, if my array was size 15, dividing it by 3 will give me arrays of size 5, which means I'm splitting an XYZ coordinate.
How can I split this array (it doesn't have to necessarily be equal in size) so that I can distribute the work? (for instance, in the previous example, I would like to have two arrays of size 6 and one of size 3).
Note: The size of the array is variable, but is always divisible by 3.
EDIT: Sorry, should have mentioned that I'm working in Java. My algorithm iterates through a collection of coordinates and determines which coordinates lie inside of a particular 3d shape (such as an ellipsoid). It saves these coordinates and I perform other tasks with these coordinates (I'm working on a computer graphics app).
EDIT2: I'm going to elaborate on the algorithm a bit more.
Basically, I am working in Android OpenGL-ES-3.0. I have complex 3D-object with somewhere around 230000 vertices and close to a million triangles.
In the app, the user moves either a ellipsoid or box (they choose which one) to a location close to or on the object. After moving it, they click a button, which runs my algorithm.
The purpose of the algorithm is to determine which points from my object lie inside of the ellipsoid or box. These points are subsequently changed to a different color. To add to the complexity, however, is the fact that I have transformation matrices applied to both the points of the object and the points of the ellipsoid/box.
My current algorithm begins by iterating through all the points of the object. For those of you unclear on my iteration, this is my loop.
for(int i = 0; i < numberOfVertices*3;)
{
pointX = vertices[i];
i++;
pointY = vertices[i];
i++;
pointZ = vertices[i];
i++;
//consider transformations, then run algorithm
}
I perform the necessary steps to consider all my transformations, and after that is finished, I have a point from my object and the location of my ellipsoid/box centroid.
Then, depending on the shape, one of the following algorithms is used:
Ellipsoid: I use the centroid of the ellipse and apply the formula
(x−c)T RT A R(x−c) (sorry I don't know how to format that, I'll explain the formula). x is a column vector describing the xyz point from my object that I am on in my iteration. c is a column vector describing the xyz point of my centroid. T is supposed to mean transpose. R is my rotation matrix. A is a diagonal matrix with entries with entries (1/a^2, 1/b^2, 1/c^2), and I have values for a b and c. If this formula is > 1, then x lies outside of my ellipsoid and is not a valid point. If it is <=1, then I save x.
Box: I simply check if the point falls within a range. If the point of the object lies a certain distance in the X-direction, Y-direction, and Z-direction from the centroid, I save it.
These algorithms are accurate, and work as intended. The issue, is obviously efficiency. I don't seem to have a good understanding of what makes my app strain and what doesn't. I thought multi-threading would work, and I tried some of the techniques described but they didn't have a significant improvement on performance. If anyone has ideas on filtering out my search so I'm not iterating through all these points, it would help.
May I suggest a slightly different way to handle it. I know this isn't a direct answer to your question, but please consider it.
This could be easier to see if you implemented it as coordinate Objects, each with x, y and z values. Your "array" would now be 1/3 as long. You might think this would be less efficient--and you might be right--but you'd be surprised at how well java can optimize things. Often Java optimizes for the cases people use the most and your manually manipulating this array as you suggest is possibly even slower than using objects. Until you've proven the most readable design too slow you shouldn't optimize it.
Now you have a collection of coordinate objects. Java has queues that multiple threads can pull from efficiently. Dump all your objects into a queue and have each of your threads pull one and work on it by processing it and putting it in a "Completed" queue. Note that this gives you the ability to add or remove threads easily, without effecting your code except for 1 number. How would you take the array based solution to 4 or 6 threads?
Good luck
Here is a demo of the work explained below.
Observations
Each coordinate is 3 indexes.
You have 3 threads.
Let's say you have 17 coordinates, that's 51 indexes. You want to split the 17 coordinates among your 3 threads.
var arraySize = 51;
var numberOfThreads = 3;
var numberOfIndexesPerCoordinate = 3;
var numberOfCoordinates = arraySize / numberOfIndexesPerCoordinate; //17 coordinates
Now split that 17 coordinates among your threads.
var coordinatesPerThread = numberOfCoordinates / numberOfThreads; //5.6667
This isn't an even number, so you need to distribute unevenly. We can use Math.floor and modulo to distribute.
var floored = Math.floor(coordinatesPerThread); //5 - every thread gets at least 5.
var modulod = numberOfCoordinates % floored; // 2 - there will be 2 left that need to be placed sequentially into your thread pool
This should give you all the information you need. Without knowing what language you are using, I don't want to give any real code samples.
I see you edited your question to specify Java as your language. I'm not going to do the threading work for you, but I'll give a rough idea.
float[] coordinates = new float[17 * 3]; //17 coordinates with 3 indexes each.
int numberOfThreads = 3;
int numberOfIndexesPerCoordinate = 3;
int numberOfCoordinates = coordinates.length / numberOfIndexesPerCoordinate ; //coordinates * 3 indexes each = 17
//Every thread has this many coordinates
int coordinatesPerThread = Math.floor(numberOfCoordinates / numberOfThreads);
//This is the number of coordinates remaining that couldn't evenly be split.
int remainingCoordinates = numberOfCoordinates % coordinatesPerThread
//To make things easier, I'm just going to track the offset in the original array. It could probably be computed instead, but its just an int.
int offset = 0;
for (int i = 0; i < numberOfThreads; i++) {
int numberOfIndexes = coordinatesPerThread * numberOfIndexesPerCoordinate;
//If this index is one of the remainders, then increase by 1 coordinate (3 indexes).
if (i < remainingCoordinates)
numberOfIndexes += numberOfIndexesPerCoordinate ;
float[] dest = new float[numberOfIndexes];
System.arraycopy(coordinates, offset, dest, 0, numberOfIndexes);
offset += numberOfIndexes;
//Put the dest array of indexes into your threads.
}
Another, potentially better option would be to use a Concurrent Deque that has all of your coordinates, and have each thread pull from it as they need a new coordinate to work with. For this solution, you'd need to create Coordinate objects.
Declare a Coordinate object
public static class Coordinate {
protected float x;
protected float y;
protected float z;
public Coordinate(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
}
Declare a task to do your work, and pass it your concurrent deque.
public static class CoordinateTask implements Runnable {
private final Deque<Coordinate> deque;
public CoordinateTask(Deque<Coordinate> deque) {
this.deque = deque;
}
public void run() {
Coordinate coordinate;
while ((coordinate = this.deque.poll()) != null) {
//Do your processing here.
System.out.println(String.format("Proccessing coordinate <%f, %f, %f>.",
coordinate.x,
coordinate.y,
coordinate.z));
}
}
}
Here's the main method showing the example in action
public static void main(String []args){
Coordinate[] coordinates = new Coordinate[17];
for (int i = 0; i < coordinates.length; i++)
coordinates[i] = new Coordinate(i, i + 1, i + 2);
final Deque<Coordinate> deque = new ConcurrentLinkedDeque<Coordinate>(Arrays.asList(coordinates));
Thread t1 = new Thread(new CoordinateTask(deque));
Thread t2 = new Thread(new CoordinateTask(deque));
Thread t3 = new Thread(new CoordinateTask(deque));
t1.start();
t2.start();
t3.start();
}
See this demo.
Before trying to optimize with concurrency, try to minimize the amount of points you need to test, and minimize the cost of those tests, by using the most efficient collision detection methods at your disposal.
Some general suggestions:
Consider normalizing everything to a common frame of reference before running through your calculations. For example, instead of applying transformations to each point, transform the selection box/ellipsoid into the shape's coordinate system so you can perform your collision detection without the transformations within each iteration.
You may also be able to combine some or all of your transformations (rotation, translation, etc.) into a single matrix calculation, but that won't gain you much unless you're performing a lot of transformations, which you should try to avoid.
Generally speaking it's beneficial to keep the transformation pipeline as streamlined as possible, and keep all coordinate calculations in the same space to avoid transformations as much as possible.
Try to minimize the number of points you need to perform your slowest calculations on. The most accurate collision test should only be necessary for points that you can't rule out as being inside the shape by faster means, using an approximation of the shape, such as a collection of spheres, or the shape's convex hull. Simplifying the shape allows you to limit the slowest calculations to only those points that lie very close to your shape's actual bounds.
In my own 2D work in the past I found that even calculating the convex hulls for hundreds of complex animated shapes in real time was faster than doing collision detection directly without using their convex hulls, because they enable much faster collision calculations.
Consider calculating/storing additional information about the shape, such as an inner and outer collision sphere (one sphere inside all points, and one outside all points) which you can use as a fast initial filter. Anything inside the smaller sphere is guaranteed to be inside your shape, anything outside the outer sphere is known to be outside your shape. You might even want to store a simplified version of your shape, (or its convex hull), which you could calculate in advance and use to aid collision detection.
Similarly, consider using one or more spheres to approximate your ellipsoid in initial calculations, to minimize which points you need to test for collision.
Instead of calculating actual distances, calculate the squared distances and use those for comparison. However, prefer using faster tests for collision if possible. For example, for convex polygons you can use the Separating Axis Theorem, which projects vertices onto a common axis/plane to permit very quick overlap calculations.
I am implementing collision detection in my game, and am having a bit of trouble understanding how to calculate the vector to fix my shape overlap upon collision.
Say for example, I have two squares. squareA and squareB. For both of them, I know their xCo, yCo, width and height. squareA is moving however, so he has a velocity magnitude, and a velocity angle. Let's pretend I update the game once a second. I have illustrated the situation below.
Now, I need a formula to get the vector to fix the overlap. If I apply this vector onto the red square (squareA), they should not be overlapping anymore. This is what I am looking to achieve.
Can anyone help me figure out the formula to calculate the vector?
Bonus points if constructed in Java.
Bonus bonus points if you type out the answer instead of linking to a collision detection tutorial.
Thanks guys!
Also, how do I calculate the new velocity magnitude and angle? I would like sqaureA to continue moving along the x axis (sliding along the top of the blue square)
I had an function that looked something like this:
Position calculateValidPosition(Position start, Position end)
Position middlePoint = (start + end) /2
if (middlePoint == start || middlePoint == end)
return start
if( isColliding(middlePont) )
return calculateValidPosition(start, middlePoint)
else
return calculate(middlePoint, end)
I just made this code on the fly, so there would be a lot of room for improvements... starting by not making it recursive.
This function would be called when a collision is detected, passing as a parameter the last valid position of the object, and the current invalid position.
On each iteration, the first parameter is always valid (no collition), and the second one is invalid (there is collition).
But I think this can give you an idea of a possible solution, so you can adapt it to your needs.
Your question as stated requires an answer that is your entire application. But a simple answer is easy enough to provide.
You need to partition your space with quad-trees
You seem to indicate that only one object will be displaced when a collision is detected. (For the case of multiple interpenetrating objects, simply correct each pair of objects in the set until none are overlapping.)
Neither an elastic nor an inelastic collision is the desired behavior. You want a simple projection of the horizontal velocity (of square A), so Vx(t-1) = Vx(t+1), Vy(t-1) is irrelevant and Vy(t+1)=0. Here t is the time of collision.
The repositioning of Square A is simple.
Define Cn as the vector from the centroid of A to the vertex n (where the labeling of the vertices is arbitrary).
Define A(t-1) as the former direction of A.
Define Dn as the dot product of A(t-1) and the vector Cn
Define Rn as the width of A measured along Cn (and extending past the centroid in the opposite direction).
Define Sn as the dilation of B by a radius of Rn.
Let j be the vertex of B with highest y-value.
Let k be the vertex that is most nearly the front corner of A [in the intuitive sense, where the value of Dn indicates that Ck is most nearly parallel to A(t-1)].
Let K be the antipodal edge or vertex of A, relative to k.
Finally, translate A so that k and j are coincident and K is coincident with Sk.
I'm trying to write a 2D game in Java that uses the Separating Axis Theorem for collision detection. In order to resolve collisions between two polygons, I need to know the Minimum Translation Vector of the collision, and I need to know which direction it points relative to the polygons (so that I can give one polygon a penalty force along that direction and the other a penalty force in the opposite direction). For reference, I'm trying to implement the algorithm here.
I'd like to guarantee that if I call my collision detection function collide(Polygon polygon1, Polygon polygon2) and it detects a collision, the returned MTV will always point away from polygon1, toward polygon2. In order to do this, I need to guarantee that the separating axes that I generate, which are the normals of the polygon edges, always point away from the polygon that generated them. (That way, I know to negate any axis from polygon2 before using it as the MTV).
Unfortunately, it seems that whether or not the normal I generate for a polygon edge points towards the interior of the polygon or the exterior depends on whether the polygon's points are declared in clockwise or counterclockwise order. I'm using the algorithm described here to generate normals, and assuming that I pick (x, y) => (y, -x) for the "perpendicular" method, the resulting normals will only point away from the polygon if I iterate over the vertices in clockwise order.
Given that I can't force the client to declare the points of the polygon in clockwise order (I'm using java.awt.Polygon, which just exposes two arrays for x and y coordinates), is there a mathematical way to guarantee that the direction of the normal vectors I generate is toward the exterior of the polygon? I'm not very good at vector math, so there may be an obvious solution to this that I'm missing. Most Internet resources about the SAT just assume that you can always iterate over the vertices of a polygon in clockwise order.
You can just calculate which direction each polygon is ordered, using, for example, the answer to this question, and then multiply your normal by -1 if the two polygons have different orders.
You could also check each polygon passed to your algorithm to see if it is ordered incorrectly, again using the algorithm above, and reverse the vertex order if necessary.
Note that when calculating the vertex order, some algorithms will work for all polygons and some just for convex polygons.
I finally figured it out, but the one answer posted was not the complete solution so I'm not going to accept it. I was able to determine the ordering of the polygon using the basic algorithm described in this SO answer (also described less clearly in David Norman's link), which is:
for each edge in polygon:
sum += (x2 - x1) * (y2 + y1)
However, there's an important caveat which none of these answers mention. Normally, you can decide that the polygon's vertices are clockwise if this sum is positive, and counterclockwise if the sum is negative. But the comparison is inverted in Java's 2D graphics system, and in fact in many graphics systems, because the positive y axis points downward. So in a normal, mathematical coordinate system, you can say
if sum > 0 then polygon is clockwise
but in a graphics coordinate system with an inverted y-axis, it's actually
if sum < 0 then polygon is clockwise
My actual code, using Java's Polygon, looked something like this:
//First, find the normals as if the polygon was clockwise
int sum = 0;
for(int i = 0; i < polygon.npoints; i++) {
int nextI = (i + 1 == polygon.npoints ? 0 : i + 1);
sum += (polygon.xpoints[nextI] - polygon.xpoints[i]) *
(polygon.ypoints[nextI] + polygon.ypoints[i]);
}
if(sum > 0) {
//reverse all the normals (multiply them by -1)
}
I am using Java's InterpolationBilinear class to help me resample an array. My current (and relatively small) test case is transforming a 10x10 array into a 20x20 array. My issue is that the interpolate(double[][], float x, float y) method in this class is only resampling the upper-left corner of the 2D array I send it (0x0, 0x1, 1x0, 1x1).
Currently, it looks like I'll have to write some code to send the interpolate method a bunch of 2x2 arrays instead of the whole array. There just seems to be a better way, any tips?
I am not interested in using 3rd party libraries, only standard Java and code I can write myself.
Thanks!
That's what the InterpolationBilinear class is supposed to do. See the documentation. The only thing it does is implement bilinear interpolation between four points arranged in a rectangle. The formula is explained here, and you can also implement it yourself pretty easily.
The question is: what are float x and float y in your example? For InterpolationBilinear.interpolate they're supposed to represent the fractional position between the four corners of the sample rectangle.
Or do you want float x and float y to represent element numbers in your array? e.g. (4.3,7.1) would mean interpolating between elements (4,7), (4,8), (5,7), and (5,8)? Then yes, you just have to plug those four values into interpolate (or your own implementation of that simple formula) along with the fractional positions 0.3 in x and 0.1 in y.
EDIT You have now clarified that x and y should represent the fractional position in the array, let's call it raw[][], and assume it's 10 x 10 i.e. indices go from 0 to 9 in both dimensions.
To interpolate at (x,y) you just need to find what square (x,y) falls into, and interpolate between the four corners. In the x direction, the indices will be the integers immediately above and below x*9, i.e. Math.floor(x*9) and Math.floor(x*9) + 1 -- same idea in y but with y*9. Now you have your four corners. Plug them into the formula. The fractional position will be something like xfrac = x*9 - Math.floor(x*9) and yfrac = y*9 - Math.floor(y*9). Plug those in the formula as well.
This has to be repeated for each point in your target array. Note that the x in the paragraph above will be equal to i/19 and the y equal to j/19 where i and j are the indices of your target array.