views:

94

answers:

6

Lets say I've got two squares and I know their positions, a red and blue square:

redTopX;
redTopY;
redBotX;
redBotY;
blueTopX;
blueTopY;
blueBotX;
blueBotY;

Now, I want to check if square blue resides (partly) within (or around) square red. This can happen in a lot of situations, as you can see in this image I created to illustrate my situation better: alt text

Note that there's always only one blue and one red square, I just added multiple so I didn't have to redraw 18 times.

My original logic was simple, I'd check all corners of square blue and see if any of them are inside square red:

if (
((redTopX >= blueTopX) && (redTopY >= blueTopY) && (redTopX <= blueBotX) && (redTopY <= blueBotY)) || //top left
((redBotX >= blueTopX) && (redTopY >= blueTopY) && (redBotX <= blueBotX) && (redTopY <= blueBotY)) || //top right
((redTopX >= blueTopX) && (redBotY >= blueTopY) && (redTopX <= blueBotX) && (redBotY <= blueBotY)) || //bottom left
((redBotX >= blueTopX) && (redBotY >= blueTopY) && (redBotX <= blueBotX) && (redBotY <= blueBotY)) //bottom right
) {
    //blue resides in red
}

Unfortunately, there are a couple of flaws in this logic. For example, what if red surrounds blue (like in situation 1)?

I thought this would be pretty easy but am having trouble coming up with a good way of covering all these situations.. can anyone help me out here?

Regards, Tom

+2  A: 

One formula for intersection of two rectangles would be

! ( (redTopX > blueBotX) || (blueTopX > redBotX) || (redTopY < blueBotY) || (blueTopY < redBotY))

You can use DeMorgan's Theorem to simplify.

Lance Roberts
+2  A: 

Assuming both squares are aligned, as you've indicated:

The squares intersect if all of the following hold:

  1. The left side of Red is left of the right side of Blue.
  2. The right side of Red is right of the left side of Blue.
  3. The top of Red is above the bottom of Blue.
  4. The bottom of Red is below the top of Blue.

(Convince yourself that this is true!)

Jesse Beder
+1  A: 
if (blueTopY < redBotY) return (0);
if (blueBotY > redTopY) return (0);
if (blueBotX < redTopX) return (0);
if (blueTopX > redBotX) return (0);
return (1); // there must clash
dalton
+1  A: 
for each blue corner:
  if corner is between all four red sides:
    return true
return false
Ignacio Vazquez-Abrams
+4  A: 

A test that checks whether red rectangle resides completely outside the blue rectangle looks as follows

bool outside = 
  redBotX > blueTopX || redTopX < blueBotX || 
  redBotY > blueTopY || redTopY < blueBotY;

Now, the negative of that will tell you whether red rectangle intersects the blue rectangle

bool intersects =
  !(redBotX > blueTopX || redTopX < blueBotX || 
    redBotY > blueTopY || redTopY < blueBotY);

If you wish, you can apply the De Morgan rule and rewrite it as

bool intersects =
  redBotX <= blueTopX && redTopX >= blueBotX && 
  redBotY <= blueTopY && redTopY >= blueBotY;

Of course, the above tests assume that the coordinates are "normalized*, i.e.

assert(redBotX <= redTopX && redBotY <= redTopY);
assert(blueBotX <= blueTopX && blueBotY <= blueTopY);

Also, the comparisons might be strict or non-strict depending on whether you consider touching rectangles as intersecting or not.

EDIT: I see that you use a different convention for rectangle coordinates: Top is the lower coordinate and Bot is the higher one, i.e.

assert(redTopX <= redBotX && redTopY <= redBotY);
assert(blueTopX <= blueBotX && blueTopY <= blueBotY);

To handle this case you just need to swap the Bot and Top coordinates in all conditions. For example, the last one will now look as follows

bool intersects =
  redTopX <= blueBotX && redBotX >= blueTopX && 
  redTopY <= blueBotY && redBotY >= blueTopY;
AndreyT
This is a great answer!
Arrieta
I mistakenly accepted your answer before testing it, it doesn't actually work. redBotX <= blueTopX for example fails on most of the situations shown in the image I created.
Tom
(Since all the examples above need to return true, whether you look if red is inside blue or blue is inside red.)
Tom
Tom
@Tom: Everything in the answer works perfectly. The only thing is that in the answer I assumed different representation of a rectangle (I clearly stated it at the end - see the assertions). In my assumption `Bot` stands for minimum coordinate and `Top` stands for maximum. I.e. each rectangle is represented by its lower-left and upper-right corners. In your case it is lower-right and upper-left. If you insist on your representation, just update the comparisons (swap `...BotX` and `...TopX` everywhere). Although I'd say that your initial representation is rather... weird (why?).
AndreyT
Coordinates always go from lowest (top) to highest (bottom). Look at your screen resolution for example. Top means TopLeft X and Y while Bot means BottomRight X and Y.
Tom
@Tom: Well, it is a matter of choosing the axis direction and rectangle corners. I prefer mathematical directions: X goes to the right and Y goes to the up. But in any case, it is weird to the the word `Top` used for *lower* coordinate and the word `Bot` for the *higher* one. This might make some sense for `Y` axis (because of the screen), but for `X` axis it is just weird. In any case, all you need to do is to swap `Bot` and `Top` in my answer to get the right conditions for your specific case.
AndreyT
@Tom: Note also, that even in conventions with Y axis pointing down it is customary to use bottom-left (actual bottom) and top-right (actual top) corners to represent the rectangle. Bot again it is still totally up to you to choose the representation. Just rewrite the comparisons properly.
AndreyT
I see what you mean. I chose my coordinate system to reflect the coordinate system of the flash platform. When you increase y to a flash display object, it will move down. When you increase x, it will move right. This seems to be common practice from what I have seen, but it looks like it depends on what you're used work with. BotRight and TopLeft would probably be a better terminology for me to use though. Thanks for all the help.
Tom
+1  A: 

For higher-dimensional ranges or if you want to check a lot of ranges it might be worthwhile to store your ranges (e.g. their centers) in a R tree and search for it for where the corners of your range are.

honk