12

I have found the solution but wanted to ensure my logic is the most efficient. I feel that there is a better way. I have the (x,y) coordinate of the bottom left corner, height and width of 2 rectangles, and i need to return a third rectangle that is their intersection. I do not want to post the code as i feel it is cheating.

  1. I figure out which is furthest left and highest on the graph.
  2. I check if one completely overlaps the other, and reverse to see if the other completely overlaps the first on the X axis.
  3. I check for partial intersection on the X axis.
  4. I basically repeat steps 2 and 3 for the Y axis.
  5. I do some math and get the points of the rectangle based on those conditions.

I may be over thinking this and writing inefficient code. I already turned in a working program but would like to find the best way for my own knowledge. If someone could either agree or point me in the right direction, that would be great!

Doug B
  • 175
  • 1
  • 1
  • 7
  • I don't know if this would help, but it deals with determining the collesion point of a moving object ... [example](http://stackoverflow.com/questions/13261767/java-ball-object-doesnt-bounce-off-of-drawn-rectangles-like-its-supposed-to/13263022#13263022) – MadProgrammer Jan 31 '13 at 01:11
  • Definitely appreciated! I thought it might have to do with that. I couldn't find anything on the internet that reduced it down to my specific example. Hopefully what i did was close enough to efficient. Thank you! – Doug B Jan 31 '13 at 01:16

3 Answers3

21

Why not use JDK API to do this for you?

Rectangle rect1 = new Rectangle(100, 100, 200, 240);
Rectangle rect2 = new Rectangle(120, 80, 80, 120);
Rectangle intersection = rect1.intersection(rect2);

To use java.awt.Rectangle class, the parameters of the constructor are: x, y, width, height, in which x, y are the top-left corner of the rectangle. You can easily convert the bottom-left point to top-left.


I recommend the above, but if you really want to do it yourself, you can follow the steps below:

say (x1, y1), (x2, y2) are bottom-left and bottom-right corners of Rect1 respectively, (x3, y3), (x4, y4) are those of Rect2.

  • find the larger one of x1, x3 and the smaller one of x2, x4, say xL, xR respectively
    • if xL >= xR, then return no intersection else
  • find the larger one of y1, y3 and the smaller one of y2, y4, say yT, yB respectively
    • if yT >= yB, then return no intersection else
    • return (xL, yB, xR-xL, yB-yT).

A more Java-like pseudo code:

// Two rectangles, assume the class name is `Rect`
Rect r1 = new Rect(x1, y2, w1, h1);
Rect r2 = new Rect(x3, y4, w2, h2);

// get the coordinates of other points needed later:
int x2 = x1 + w1;
int x4 = x3 + w2;
int y1 = y2 - h1;
int y3 = y4 - h2;

// find intersection:
int xL = Math.max(x1, x3);
int xR = Math.min(x2, x4);
if (xR <= xL)
    return null;
else {
    int yT = Math.max(y1, y3);
    int yB = Math.min(y2, y4);
    if (yB <= yT)
        return null;
    else
        return new Rect(xL, yB, xR-xL, yB-yT);
}

As you see, if your rectangle was originally defined by two diagonal corners, it will be easier, you only need to do the // find intersection part.

shuangwhywhy
  • 5,475
  • 2
  • 18
  • 28
  • I had to do this for an assignment otherwise i would just use the jdk api. Thats similar to the idea I had, but done much better and simpler. Thank you for the input! – Doug B Jan 31 '13 at 04:42
  • I think both int xR = Math.max(x2, x4) and int yB = Math.max(y2, y4) should be changed to Math.min(...) – user800183 Jan 25 '14 at 06:06
  • @WilliamMorrison, Sorry guys, the original pseudo code was incompatible with the inline steps, I have corrected it. – shuangwhywhy Jan 26 '14 at 03:26
  • @user800183, Sorry guys, the original pseudo code was incompatible with the inline steps, I have corrected it. – shuangwhywhy Jan 26 '14 at 03:26
  • A warning should be added so that the user knows that this will not work if the two rectangles do not intersect. You will end up with a rectangle that is oddly shaped as a result. E.g. you could end up with one with negative height and/or width. Always ensure that the two rectangles intersect with r1.intersects(r2) first before trying to get the intersection! – Chthonic One Sep 08 '22 at 22:55
13

My variation of determining intersection of two rectangles in a small utility function.

//returns true when intersection is found, false otherwise.
//when returning true, rectangle 'out' holds the intersection of r1 and r2.
private static boolean intersection2(Rectangle r1, Rectangle r2,
        Rectangle out) {
    float xmin = Math.max(r1.x, r2.x);
    float xmax1 = r1.x + r1.width;
    float xmax2 = r2.x + r2.width;
    float xmax = Math.min(xmax1, xmax2);
    if (xmax > xmin) {
        float ymin = Math.max(r1.y, r2.y);
        float ymax1 = r1.y + r1.height;
        float ymax2 = r2.y + r2.height;
        float ymax = Math.min(ymax1, ymax2);
        if (ymax > ymin) {
            out.x = xmin;
            out.y = ymin;
            out.width = xmax - xmin;
            out.height = ymax - ymin;
            return true;
        }
    }
    return false;
}
William Morrison
  • 10,953
  • 2
  • 31
  • 48
  • @rob read more carefully. `out` contains the intersection, if it exists. There's even documentation explaining that... Also, its more readable as the variables are named more clearly. Let me know if I can clear anything else up for you. – William Morrison Feb 27 '14 at 16:25
  • Bah! Just saw the `out` parameter so it is right if you want to make a nominal change I'll remove the down vote. I still say it's not that readable (remember, your own code is always readable, that doesn't mean someone else can read it) but that's a border line religious argument and this is math we are talking about. – rjzii Feb 27 '14 at 22:05
  • That's definitely true. I've edited my answer to remove comments on readability @rob – William Morrison Feb 28 '14 at 01:43
  • Cool, the reason that this one is correct over the accepted answer still isn't obvious though, you might want to elaborate on that as well. – rjzii Feb 28 '14 at 04:21
  • `float xmin = Math.max(r1.x, r2.x);` Xmin equals Math.Max? That's confusing – Alejandro Garcia Dec 25 '14 at 12:41
  • @AlejandroGarcia that's why I edited the answer to remove talk of readability. Its an opinion-based statement, and I do admit it could be improved some here. – William Morrison Dec 28 '14 at 02:59
  • Can you add some explanation as to why the accepted answer is incorrect and how your answer differs, making it correct? – Tot Zam Oct 01 '17 at 16:26
  • The accepted answer has been corrected in response to my prompting. Due to this, I'll be adjusting my answer to not include references to the accepted answer. There is a history within the accepted answer containing the errors which anyone can review if they are curious. – William Morrison Dec 16 '19 at 16:50
5

You can also use the Rectangle source code to compare with your own algorithm:

/**
 * Computes the intersection of this <code>Rectangle</code> with the
 * specified <code>Rectangle</code>. Returns a new <code>Rectangle</code>
 * that represents the intersection of the two rectangles.
 * If the two rectangles do not intersect, the result will be
 * an empty rectangle.
 *
 * @param     r   the specified <code>Rectangle</code>
 * @return    the largest <code>Rectangle</code> contained in both the
 *            specified <code>Rectangle</code> and in
 *            this <code>Rectangle</code>; or if the rectangles
 *            do not intersect, an empty rectangle.
 */
public Rectangle intersection(Rectangle r) {
    int tx1 = this.x;
    int ty1 = this.y;
    int rx1 = r.x;
    int ry1 = r.y;
    long tx2 = tx1; tx2 += this.width;
    long ty2 = ty1; ty2 += this.height;
    long rx2 = rx1; rx2 += r.width;
    long ry2 = ry1; ry2 += r.height;
    if (tx1 < rx1) tx1 = rx1;
    if (ty1 < ry1) ty1 = ry1;
    if (tx2 > rx2) tx2 = rx2;
    if (ty2 > ry2) ty2 = ry2;
    tx2 -= tx1;
    ty2 -= ty1;
    // tx2,ty2 will never overflow (they will never be
    // larger than the smallest of the two source w,h)
    // they might underflow, though...
    if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE;
    if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE;
    return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
}