Can someone guide me how I can implement the following in java: I need to reference two rectangles after splitting from any rectilinear polygon into two or more pieces.
Polygon http://img853.imageshack.us/img853/2475/picture1eu.jpg
My Algorithm:
ArrayList coordinates;
for (int a = 0; a < coordinates.size(); a++)
{
if (coordinates[a] at point of concave)
{
Draw intersecting line North Or South from coordinates[a] depending on
which direction remains inside the polygon.
}
}
On this particular diagram both concave edges lie on the same x-axis, however this is not always the case.
I'm guessing I need to use the Shape and Area class? I guess what I'm struggling with the most is what do I use to make the split (regular .drawLine?) and then be able to reference the two rectangles afterwards.
Thank you.
You can get list of possible rectangles finding all possible combinations of 4 vertexes. Then leave only rectangles (check x and y of neighbour vertexes). Then check whether they intersect each other.
Also they should be inside main Shape (use contains()) method of Area created from the Polygon.
Does it work?
Related
I want to shade a polygon with lines which are drawn in a specific angle.
I already have found all points with a scanline algorithm of the polygon in an ArrayList of ArrayList of Points.
This means in the ArrayList<ArrayList<Point>> are ArrayList<Point> which have all Points for a Polygon with one y value. For example these 2 Points for a rectangle (2,2) and (5,2). So the outer ArrayList contains all the horizontal points which can be drawn with drawLine().
Now I have to calculate the end points x2 and y2 for drawLine(x1,y1,x2,y2).
Is there any possibility to get the right points of the polygon for x2 and y2?
Trying to achieve this manually is rather difficult.
Consider setting the clip path in Graphics2D using your polygon as a Shape. Then, from points on the base line of the bounding rectangle of your polygon, draw the shading lines long enough to exceed the parallel line of the bounding rectangle.
You can look on wikipedia for how to find line-line intersections.
The only difficulty is making sure that the intersection is actually on the right side of the line segment. One option is just to check that the coordinates of the intersection are in the boundary of the rectangle formed by the two endpoints of the polygon side. You can easily do this by just comparing the coordinates.
Once you have found the intersection for that line on both sides of the polygon, you can then use g.drawLine() to connect them.
The naive, and simple solution to finding the two sides of the polygon (as long as it's convex), is to loop over all of the sides until you find two that have the intersection in the bounds of the side. Then, just connect those two intersections.
I am making a game in which the user player places circles on the screen. It is important that the circles never overlap, so I need to figure out the nearest possible free spot from the cursor. I have found circle packing algorithms, but they do not seem a fit for my problem. I have also solved a similar problem in the past for boxes (here), but with circles, I cannot seem to figure it out.
I figured out how I can find the nearest free position when it intersects with one circle, or even when two are involved. However, I cannot find a robust algorithm that can deal with complex cases that have any number of circles in any arrangement.
Precise description of problem:
I have a 2D space with any number of non-intersecting circles, all with identical radii (though that may not matter). I want to find a position for the next circle that will make it not intersect with any other circle, and which center [x,y] is nearest to a specified location [x,y].
Suggestions of any kind appreciated (references, approaches, or (Java) libraries).
p.s. Bonus points if the solution includes making sure the circle stays within a specific bounding box (i.e. display).
My final solution: (based on David Wallace's suggestions)
Calculate the minimal distance between the centers of two circles (in my case, all circles are the same size, so always 2*radius)
Make a list of all circles that are closer to the mouse position than the minimum distance
If 0 overlaps: all good!
If 1 overlap: move the new circle's center to the minimum distance from the compared circle's center, along the vector that runs from compared circle's center to mouse position
If 2 overlap: find out where the two overlapping circles intersect. Place the new circle on the intersection closest to the mouse position. If this position still overlaps with any circle, move to the other intersection. If that one doesn't work, leave the new circle were it is.
If 3 overlap: same as in 2 overlap, just take the two circles closest to the new circle.
Note that this does not work perfectly, but good enough in my case, where a user is dragging the new circle on the screen. It works in most cases and in those it doesn't, usually when there are many circles very close together, the new circle simply stays in the last position (which was valid). The user can then decide to drag it a fit further and be more precise in where he wants the new circle to go.
This isn't a complete answer, but you may be able to make it into one.
Suppose you've already placed circles of radii r1, r2, r3 ... rn with centres C1, C2, C3 ... Cn, and you're looking to place a new circle of radius rz, the new circle's centre will have to be outside all of a set of "enlarged" circles, centred at C1, C2, C3 ... Cn; with radii (r1+rz), (r2+rz), (r3+rz) ... (rn+rz). So if the cursor is at point P, then there are some cases to consider.
(1) If P is not in any of the enlarged circles, then the problem is solved.
(2) If P is in just one of the enlarged circles, then move outwards along a radius of that circle, until you either reach a point that's outside all of the enlarged circles, or until you reach another enlarged circle. The former case reduces to scenario (1); the latter reduces to scenario (2). Pick an arbitrary direction if P happens to be the centre of the circle.
(3) If P is in several of the circles, then find the directions from P to each centre of a circle that it's in. Find the pair of directions that have the widest interval between them, and bisect that angle, to work out which direction to head along. For example, if the directions to the centres of the circles are 30deg, 120deg and 330deg, then bisect the angle between 120deg and 330deg - then head in a direction of 225deg. Head in that direction until you reach the edge of a circle, then recalculate. Keep doing this until you get back to scenario (2).
The thing that I can't work out is what to do if you get stuck in scenario (3). Maybe only allow a certain number of steps, then exit. After all, it's possible that there's no suitable place to put the circle.
To calculate the distance between a point and a circle is with the center, considering your Circle class is like this one:
public class Circle{
int x;
int y;
int radius;
}
public interface CircleHelper{
public int distanceBetweenCircleAndPoint(Circle c, Point p);
public int distanceBetweenTwoCircles(Circle c1, Circle c2);
}
First of all, I would think about using Quadtrees and check if there is any quad without surrounding circles
The quadtree deep can be selected considering the radius of the circles.
so if you have a point in one of the quads, you would look to its surrounding quads to check if there is any circle there and move from the point in the direction of empty quads.
I hope you understand my approach
Here is a solution that will work for varying radiuses, and can be simplified if all radiuses are equal, as in your case. We first transform the problem slightly. Instead of fitting a circle among other circles, we extend the radiuses of all other circles by the radius of our circle to place, and instead try to place a point outside of these extended circles. This is equivalent to the original problem. We proceed as follows:
First a special case. If the point is outside of all circles, we have a trivial solution.
Find all the circles the point is inside. Calculate the closest point on their circumference (just move out from the original point along the radius).
Find all the intersection points between pairs of circles.
Combine the sets of points from steps 2 and 3, and filter these by finding the ones that are not covered by any other circle.
Pick the closest point from the remaining set. Done!
This seems to be O(n^3), so not terribly fast, but should be doable if your set is not too huge.
I am currently working on a simple space game for android. My collision detection will be done using rectangular and circular bounding boxes. These bounding boxes need to be able to rotate, so my question is: what is the best to detect a collision between a rotated rectangle and a circle? Thanks for your help :)
Ok, I have solved my own problem! There are only two cases when a circle intersects a rectangle:
1. The center of the circle is inside the rectangle
2. The circle is intersecting one of the sides of the rectangle
So to check for the collision, I first check if the center of the circle is inside the rectangle, after rotating the center of the circle according to the rotation of the rectangle, to simplify my calculations. If the center of the circle is inside the rectangle, I know there is an intersection, and return true.
If the first check returns false, then I check for intersections between each side of the rectangle, and the circle. If there is an intersection I return true. Feel free to comment if anyone wants the code, thanks for the help guys! :)
Generally, bounding boxes just define the bounds of an object, (a shape generated by the vertices of an object's max & min's X & Y) - this makes it much simpler to calculate, bounding boxes do not need to rotate as their purpose is met simply as I have explained. If you want to use them for collision detection simply check if the center of the circle plus its radius intersects the rectangle in both axis such as:
public boolean boxintersectscircle(BoundingBox box, BoundingCircle circle) {
if (box.x > circle.centerx+circle.radius) return false;
if (box.y > circle.centery+circle.radius) return false;
if (box.x+box.width < circle.centerx-circle.radius) return false;
if (box.y+box.height < circle.centery-circle.radius) return false;
return true;
}
However bounding boxes aren't accurate - they can leave a lot of unoccupied space so if that's a worry for your game (player frustration), Personally I would implement the separating axis theorem or line/circle detection.
I'm trying to draw a hexagon shaped asteroid on a clone of Asteroids I'm making for a class.
sprite = new Polygon();
sprite.addPoint(0,0);
sprite.addPoint(0,-40);
sprite.addPoint(30,-40);
sprite.addPoint(60,-10);
sprite.addPoint(60,20);
sprite.addPoint(40,50);
sprite.addPoint(-20,50);
sprite.addPoint(-50,20);
sprite.addPoint(50,-10);
sprite.addPoint(20,-40);
Yet when I do it, I end up with this
So what is going wrong? I drew it out on a coordinate plane, and copied the points over. It was my understanding that Java would draw it out in the order I listed the points, and I had the (0,0) in there in the interest of rotating the asteroid for the game.
Zane is close, he forgot to include i in his formula:
for(i=0; i<6; i++) {
sprite.addpoint(x + r*cos(i*2*pi/6), y + r*sin(i*2*pi/6))
}
First, if it is supposed to be a hexagon, then it should have 6 points, not 10. Second, just drawing this on paper from your coordinates gives me quite a similar polygon as they one in your picture. So I guess your coordinates are wrong. Check them again.
If you want to draw a symmetric hexagon, then all you need is its center, say (x,y) and its radius r. Then the points of the hexagon are
for(i=0; i<6; i++) {
sprite.addpoint(x + r*cos(i*2*pi/6), y + r*sin(i*2*pi/6))
}
It's not really a hexagon, the last two points look strange
sprite.addPoint(50,-10);
sprite.addPoint(20,-40);
Think those final two should be:
sprite.addPoint(-50,-10);
sprite.addPoint(-20,-40);
but even with that, its going to look a lop-sided pacman - back to the drawing board I think.
I would check your coordinates. The last few transitions do not look right to me, especially (-50, 20) to (50, -10). It has a jump of 100 units in the x direction, bigger than any other change in coordinates. (-50, -10) seems more plausible.
I'm creating a 2d game. There are a lot of objects(oval, triangle etc) created by Bitmap. I'm going to detect collisions. Now I can do it only with rectange like this:
int x, y;
...
if(x>=bmp.getX() && x<=bmp.getX()+bmp.getWidth()
&& y>=bmp.getY() && y<=bmp.getY()+bmp.getHeight()) {
//Collision.
}
But there is one problem: I don't know how to do it with another figure (oval, triangle, etc). Any ideas will be appreciated. Thank you.
A simple solution is to use sub rectangles to calculate collisions. The sub rectangles wont be able to cover the entire object but they can cover most of it.
This image should illustrate what I mean, it uses several rectangles for collision detection of a aeroplane
Another option (though NOT recommended) is to use per pixel color collision, if a colored pixel in the triangle intercepts a colored of an oval then there is a collision. Be warned this is computationally expensive.
1) for most figures try formula for intersection of edges
to find more try ie: How do you detect where two line segments intersect?
2) for intersection of circle and not circle, try distance from centre of circle to edgeHow to tell if a line segment intersects with a circle?
3) intersection of two circles is easiest, just check is distance between both centres are lower than sum of their radius
I faced the same problem as you, however with irregular Shapes. How I fixes the problem:
Create a Shape class that contains a list of Rectangles.
When first creating your game object, you should add Rectangles to the list so that a Shape is formed.
Now for collision detection; instead of just checking the one rect, iterate over all the rects in the list.
I hope this helps.
For oval you can use: -
if((Math.pow(x, 2) / Math.pow(a, 2)) + (Math.pow(y, 2) / Math.pow(b, 2)) < 1) {
/** Point (x, y) is inside Oval **/
}
For Triangle, it is a little trivial task: -
Visit this link