views:

15646

answers:

12

I'm looking for an algorithm to detect if two rectangles intersect (one at an arbitrary angle, the other with only vertical/horizontal lines).

Testing if a corner of one is in the other ALMOST works. It fails if the rectangles form a cross-like shape.

It seems like a good idea to avoid using slopes of the lines, which would require special cases for vertical lines.

A: 

what if you add to your corner check, a check to see if the second rectangle is inside the bounds (rectangular) of the angled rectangle?

Wes P
that can miss cases where they overlap but no corner is inside any rectangle
Florian Bösch
A: 

What language are you gonna do this in? Because in Java there are built-in classes that let you do this.

Martijn
A: 

I think graphics api and most GUI libraries(like swing) has this implemented.

l_39217_l
Unfortunately I don't think .NET has this.
A: 

If you're using Java, all implementations of the Shape interface have an intersects method that take a rectangle.

bcash
Unfortunately I'm using C#. The Rectangle class has a Contains () method, but it's only for non-rotated rectangles.
A: 

Well, the brute force method is to walk the edges of the horizontal rectangle and check each point along the edge to see if it falls on or in the other rectangle.

The mathematical answer is to form equations describing each edge of both rectangles. Now you can simply find if any of the four lines from rectangle A intersect any of the lines of rectangle B, which should be a simple (fast) linear equation solver.

Adam Davis
The problem with equations is when you have a vertical line, which has infinite slope.
There are corner cases for every solution.
Adam Davis
and one square entirely enclosing the other.
Oliver Hallam
+2  A: 

Check to see if any of the lines from one rectangle intersect any of the lines from the other. Naive line segment intersection is easy to code up.

If you need more speed, there are advanced algorithms for line segment intersection (sweep-line). See http://en.wikipedia.org/wiki/Line_segment_intersection

lbrandy
Careful! Don't forget the case where one rectangle completely encloses another
dysfunctor
A: 

You could find the intersection of each side of the angled rectangle with each side of the axis-aligned one. Do this by finding the equation of the infinite line on which each side lies (i.e. v1 + t(v2-v1) and v'1 + t'(v'2-v'1) basically), finding the point at which the lines meet by solving for t when those two equations are equal (if they're parallel, you can test for that) and then testing whether that point lies on the line segment between the two vertices, i.e. is it true that 0 <= t <= 1 and 0 <= t' <= 1.

However, this doesn't cover the case when one rectangle completely covers the other. That you can cover by testing whether all four points of either rectangle lie inside the other rectangle.

HenryR
+5  A: 
m_pGladiator
I assume this has to be done on both the x and y axis?
Adam Davis
Obviously, as two squares (0,0,1,1) and (0,3,1,4) do not overlap but their projections on the x axis completely overlap. Both tests are necessary, the combination is sufficient.
MSalters
Yes, both x and y axis.
m_pGladiator
Please edit the original post; I was wondering the same thing and it's not obvious to look in the comments.
Aaron Digulla
It is not sufficient for the x and y projections to overlap : take eg the rectangles [(0,0), (0,3), (3,3), (3,0)] and [(2,5), (5,2), (7,4), (4,7)].
Joel in Gö
I agree with @Joel in Gö. This method misses a large set of cases where the rectangles do not overlap, yet their projected radii do in both x and y.
Scottie T
Scottie T
As said before, this is not a full nor accurate solution
Eliram
This answer is not wrong, but it is misleading.It is true that: If the two boxes collide, the lines A and B will overlap.but it is also true that: If the lines A and B overlap, the two boxes may or may not be colliding
floater81
@floater: I would say it's *not only* wrong, but *also* misleading, which is even worse.
BlueRaja - Danny Pflughoeft
A: 

This is what I would do, for the 3D version of this problem:

Model the 2 rectangles as planes described by equation P1 and P2, then write P1=P2 and derive from that the line of intersection equation, which won't exist if the planes are parallel (no intersection), or are in the same plane, in which case you get 0=0. In that case you will need to employ a 2D rectangle intersection algorithm.

Then I would see if that line, which is in the plane of both rectangles, passes through both rectangles. If it does, then you have an intersection of 2 rectangles, otherwise you don't (or shouldn't, I might have missed a corner case in my head).

To find if a line passes through a rectangle in the same plane, I would find the 2 points of intersection of the line and the sides of the rectangle (modelling them using line equations), and then make sure the points of intersections are with in range.

That is the mathematical descriptions, unfortunately I have no code to do the above.

freespace
+49  A: 

The standard method would be to do the separating axis test (do a google search on that).

In short:

  • Two objects don't intersect if you can find a line that separates the two objects. e.g. the objects / all points of an object are on different sides of the line.

The fun thing is, that it's sufficient to just check all edges of the two rectangles. If the rectangles don't overlap one of the edges will be the separating axis.

In 2D you can do this without using slopes. An edge is simply defined as the difference between two vertices, e.g.

  edge = v(n) - v(n-1)

You can get a perpendicular to this by rotating it by 90°. In 2D this is easy as:

  rotated.x = -unrotated.y
  rotated.y =  unrotated.x

So no trigonometry or slopes involved. Normalizing the vector to unit-length is not required either.

If you want to test if a point is on one or another side of the line you can just use the dot-product. the sign will tell you which side you're on:

  // rotated: your rotated edge
  // v(n-1) any point from the edge.
  // testpoint: the point you want to find out which side it's on.

  side = sign (rotated.x * (testpoint.x - v(n-1).x) + 
               rotated.y * (testpoint.y - v(n-1).y);

Now test all points of rectangle A against the edges of rectangle B and vice versa. If you find a separating edge the objects don't intersect. If you find no separating edge either the rectangles are intersecting or one rectangle is contained in the other.

The test works with any convex polygons btw..

Nils Pipenbrinck
That's cool! I learned something new today.
dysfunctor
Nice to read that, dysfunctor.
Nils Pipenbrinck
I like this approach; it's simple and logical. It seems if one rect is inside the other, all edges of the containing rect will appear to be separating edges. In this case, testing if a single point from the (possibly) contained rect is in the containing rect would tell if it's entirely contained.
This algorithm doesn't work for all cases. It is possible to place the second rectangle rotated 45 degrees to the first rectangle and offset along the diagonal so that it fulfills the above intersection tests but doesn't intersect.
Skizz
Skizz, check all eight edges. If the objects don't intersect one of the eight edges *will* separate them. Why don't you post an image showing your case? I can show you the axis..
Nils Pipenbrinck
My mistake, it does cope with that condition.
Skizz
Brilliant, thank you.
Adi
For 3d polyhedrons you need some additional tests, the possible separating axis are the face normals *and* the cross products of all pairs of edges (one taken from each object). These cross products are all "through the paper" in 2d so they don't need to be checked.
phkahler
A: 

One solution is to use something called a No Fit Polygon. This polygon is calculated from the two polygons (conceptually by sliding one around the other) and it defines the area for which the polygons overlap given their relative offset. Once you have this NFP then you simply have to do an inclusion test with a point given by the relative offset of the two polygons. This inclusion test is quick and easy but you do have to create the NFP first.

Have a search for No Fit Polygon on the web and see if you can find an algorithm for convex polygons (it gets MUCH more complex if you have concave polygons). If you can't find anything then email me at howard dot J dot may gmail dot com

Howard May
A: 

I don't have enough reputation to comment on Nils' answer, so my question here:

+--------+      
|   R1   |      
|        |      
|      +-+-----+
+------+-+     |
       |  R2   |
       +-------+

Obviously, all points of R2 are on the right of the left edge of R1, so only testing all points of R2 against the left edge of R1 is not enough, all the points of R1 must be also taken into account.

an0
There are four sides to R1 and Four to R2.You must test ALL 8 sides (or until you find a separating line).When testing each side (e.g. the left of R1), you first remember on which side a vertice other that the two left vertices (e.g. top-right of R1 is, and then test that ALL 4 vertices of R2 are on the opposite side. (false, in this case, since these rectangles ARE overlapping)
Eliram