Reputation: 103
Is it possible to check a collision with a line using an Area object?
Currently the way I am doing it is not working:
This returns false when you run it. But the line is very clearing touching the rectangle, in fact its completely inside it.
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
public class collision {
public static void main(String[] args) {
Area area1 = new Area(new Rectangle(0, 0, 100, 100));
Area area2 = new Area(new Line2D.Double(0, 0, 100, 100));
System.out.println(isColliding(area1, area2));
}
public static boolean isColliding(Area area1, Area area2) {
if (area2 != null) {
Area collide1 = new Area(area1);
collide1.subtract(area2);
if (!collide1.equals(area1)) {
return true;
}
}
return false;
}
}
Upvotes: 2
Views: 1704
Reputation: 103
I was able to solve this problem by making a recursive function that checks points along the thing. The higher you set the depth the more accurately it will check, but will take longer to complete. I have been using 10 as my depth (which I believe checks 2047 points along the line) and I encountered no performance loss. Unless your Area object contains really thin parts I don't believe you will need more than this.
Someone feel free to comment and revise my method if you believe you can improve it in any way :)
Thanks to ajb for his suggestion of using a PathIterator which gave me the idea to check points along the line.
public static boolean findPoints(Area area1, Line2D line1, int depth) {
Point p1 = new Point((int) (line1.getX2() + line1.getX1()) / 2,
(int) (line1.getY2() + line1.getY1()) / 2);
if (depth == 0) {
return false;
}
pointMiddle = new Point(p1);
if (area1.contains(p1)) {
return true;
} else {
return findPoints(area1, new Line2D.Double(p1, line1.getP2()),
depth - 1)
|| findPoints(area1, new Line2D.Double(line1.getP1(), p1),
depth - 1);
}
}
Upvotes: 1
Reputation: 31689
If, as you say in the comments, you know that you will always be checking a Line2D
and a Rectangle
for collision, you can use the intersects
method of Line2D
(see javadoc):
public static void main(String[] args) {
Rectangle rect1 = new Rectangle(0, 0, 100, 100);
Line2D line2 = new Line2D.Double(0, 0, 100, 100);
System.out.println(isColliding(rect1, line2));
}
public static boolean isColliding(Rectangle2D rect1, Line2D line2) {
if (line2 != null) {
return line2.intersects(rect1);
}
return false;
}
To test if a line collides with a more general Area
is more difficult; I don't think there's a method in the library for this. If the Area
is built up of rectangles, you could try saving an array (or List
) of the Rectangle
objects, and testing whether the line intersects with any of them. Another approach: You can try using the contains
method of Area
, which tests whether an area contains a point. If either endpoint of the Line2D
is contained by the Area
, then the line and the area collide. If both endpoints are outside the area, but the area consists of straight lines (area.isPolygonal()
), you could retrieve each line segment from the polygon and test whether the line intersects each line segment. You can do this with area.getPathIterator(null)
, and then using something like this on the resulting path iterator:
double[] coords = new double[6];
double moveX, moveY, prevX, prevY, newX, newY;
while (!pathIterator.isDone()) {
switch (pathIterator.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
moveX = coords[0]; moveY = coords[1];
prevX = moveX; prevY = moveY;
break;
case PathIterator.SEG_LINETO:
newX = coords[0]; newY = coords[1];
if ([line2 intersects the line from (prevX,prevY) to (newX,newY)]) {
return true;
}
prevX = newX; prevY = newY;
break;
case PathIterator.SEG_QUADTO:
case PathIterator.SEG_CUBICTO:
throw new RuntimeException("What is a curve doing in my rectangle?");
case PathIterator.SEG_CLOSE:
// go back to the last SEG_MOVETO point, usually the first point
if ([line2 intersects the line from (prevX,prevY) to (moveX,moveY)]) {
return true;
}
prevX = newX; prevY = newY;
break;
}
}
There are methods in Line2D
to test whether a line segment intersects another.
Note: I have not tested this at all. I hope it works.
Upvotes: 0