33

Let say that we have two rectangles, defined with their bottom-left and top-right corners. For example: rect1 (x1, y1)(x2, y2) and rect2 (x3, y3)(x4, y4). I'm trying to find the coordinates(bottom-left and top-right) of the intersected rectangle.

Any ideas, algorithm, pseudo code, would be greatly appreciated.

p.s. I found similar questions but they check only if 2 rectangle intersect.

NoSense
  • 881
  • 2
  • 11
  • 21
  • A) This is very easy to search for, I promise the internet has the answer already B) If we are talking axis aligned rectangles (which we seem to be) you should be able to reinvent the wheel quite quickly. Have you tried it yet? – David Nov 03 '13 at 12:57
  • 1
    I have searched the web but couldn't find anything helpful - most of the solutions only check if there is an intersection, don't return the coordinates of the new rectangle. Could you explain a bit more about the axis aligned rectangles, because I can't get it. p.s. Sorry for my bad english – NoSense Nov 03 '13 at 13:05
  • @Dave: For some unexplainable reason, attempts to "reinvent the wheel" for the two rectangle intersection problem produce solutions that about 4 to 8 times more "heavy" than they need to be. – AnT Nov 03 '13 at 16:15
  • @NoSense the `scheme` tag is reserved for questions about the Scheme programming language, this question is not about it, why do you keep adding the tag? – Óscar López Nov 03 '13 at 18:56
  • possible duplicate of [Java method to find the rectangle that is the intersection of two rectangles using only left bottom point, width and height?](http://stackoverflow.com/questions/14616829/java-method-to-find-the-rectangle-that-is-the-intersection-of-two-rectangles-usi) – Ted Hopp Nov 03 '13 at 19:51
  • @Óscar López - I will have to implement it to Scheme programming language :), but first need to understand the algorithm – NoSense Nov 04 '13 at 19:02

5 Answers5

65

If the input rectangles are normalized, i.e. you already know that x1 < x2, y1 < y2 (and the same for the second rectangle), then all you need to do is calculate

int x5 = max(x1, x3);
int y5 = max(y1, y3);
int x6 = min(x2, x4);
int y6 = min(y2, y4);

and it will give you your intersection as rectangle (x5, y5)-(x6, y6). If the original rectangles do not intersect, the result will be a "degenerate" rectangle (with x5 >= x6 and/or y5 >= y6), which you can easily check for.

P.S. As usual, small details will depend on whether you have to consider touching rectangles as intersecting.

AnT
  • 291,388
  • 39
  • 487
  • 734
  • 2
    This can be extended to higher dimensions too. Say a Rectangle has a U and L vectors holding the upper and lower values for all dimensions. (U for your first rectangle is [x2, y2]; L is [x1, y1]. But they could be [x, y, z, w, ...] coordinates.) Then intersection.L = pointwise_maximum(rect1.L, rect2.L); intersection.U = pointwise_minimum(rect1.U, rect2.U). Then if any(intersection.U - intersection.L < 0), the intersection is invalid (not actually an intersection). – Pavel Komarov Jul 11 '18 at 21:07
15

To look for an intersection, you will have to do some simple comparison of the points:

two rectangles

So as we can see from the image if x3, y3 is greater or equal to x1, y1 and less than or equal to x2, y2 then it is inside the first rectangle, similarly you will need to check if x4, y4 falls inside the range of x1,y1 to x2,y2 as well.

if both conditions prove to be true then you can be sure that the second rectangle is totally encompassed by the first. intersection rectangle 1 envelops rectangle 2

You will need to check the other way around as well, if finding out which is inside which is important to you.

You also have to have the rectangles be axis aligned, otherwise this will not work reliably.

Let me know if you need more detail, although I think a quick Google search will uncover much more detail for you very easily, but let me know and I can make a rectangle collision tutorial if you like.

In More Detail:

To find out if the rectangles have any intersections you can check the coordinates of their defining points, for our purposes we shall use top left and bottom right corner coordinates. We can utilise a class to make this easier for us, and to maximise on the usability of the code we can use a 2d Vector and a 2d Point: 2dVectorPoint.h

#include <cmath>

class Vector2D
{
    public:
        float   x;
        float   y;

        Vector2D() {}    
        Vector2D(float inX, float inY)
        {
            x = inX;
            y = inY;
        }

        Vector2D& Set(float inX, float inY)
        {
            x = inX;
            y = inY;
            return (*this);
        }

        float& operator [](long k)        {            return ((&x)[k]);        }

        const float& operator [](long k) const        {            return ((&x)[k]);        }

        Vector2D& operator +=(const Vector2D& v)
        {
            x += v.x;
            y += v.y;
            return (*this);
        }

        Vector2D& operator -=(const Vector2D& v)
        {
            x -= v.x;
            y -= v.y;
            return (*this);
        }

        Vector2D& operator *=(float t)
        {
            x *= t;
            y *= t;
            return (*this);
        }

        Vector2D& operator /=(float t)
        {
            float f = 1.0F / t;
            x *= f;
            y *= f;
            return (*this);
        }

        Vector2D& operator &=(const Vector2D& v)
        {
            x *= v.x;
            y *= v.y;
            return (*this);
        }

        Vector2D operator -(void) const        {            return (Vector2D(-x, -y));        }

        Vector2D operator +(const Vector2D& v) const        {            return (Vector2D(x + v.x, y + v.y));        }

        Vector2D operator -(const Vector2D& v) const        {  return (Vector2D(x - v.x, y - v.y));        }

        Vector2D operator *(float t) const        {            return (Vector2D(x * t, y * t));        }

        Vector2D operator /(float t) const        {     float f = 1.0F / t; return (Vector2D(x * , y * f));        }

        float operator *(const Vector2D& v) const        {            return (x * v.x + y * v.y);        }

        Vector2D operator &(const Vector2D& v) const     {            return (Vector2D(x * v.x, y * v.y));        }

        bool operator ==(const Vector2D& v) const        {            return ((x == v.x) && (y == v.y));        }

        bool operator !=(const Vector2D& v) const        {            return ((x != v.x) || (y != v.y));        }

        Vector2D& Normalize(void)                        {            return (*this /= sqrtf(x * x + y * y));        }

        Vector2D& Rotate(float angle);
};


class Point2D : public Vector2D
{
    public:

        Point2D() {}

        Point2D(float r, float s) : Vector2D(r, s) {}

        Point2D& operator =(const Vector2D& v)
        {
            x = v.x;
            y = v.y;
            return (*this);
        }

        Point2D& operator *=(float t)
        {
            x *= t;
            y *= t;
            return (*this);
        }

        Point2D& operator /=(float t)
        {
            float f = 1.0F / t;
            x *= f;
            y *= f;
            return (*this);
        }

        Point2D operator -(void) const{            return (Point2D(-x, -y));        }

        Point2D operator +(const Vector2D& v) const        {            return (Point2D(x + v.x, y + v.y));        }

        Point2D operator -(const Vector2D& v) const        {            return (Point2D(x - v.x, y - v.y));        }

        Vector2D operator -(const Point2D& p) const        {            return (Vector2D(x - p.x, y - p.y));        }

        Point2D operator *(float t) const        {            return (Point2D(x * t, y * t));        }

        Point2D operator /(float t) const
        {
            float f = 1.0F / t;
            return (Point2D(x * f, y * f));
        }
};


inline Vector2D operator *(float t, const Vector2D& v){    return (Vector2D(t * v.x, t * v.y));}

inline Point2D operator *(float t, const Point2D& p){    return (Point2D(t * p.x, t * p.y));}

inline float Dot(const Vector2D& v1, const Vector2D& v2){    return (v1 * v2);}

inline float Magnitude(const Vector2D& v){    return (sqrtf(v.x * v.x + v.y * v.y));}

inline float InverseMag(const Vector2D& v){    return (1.0F / sqrtf(v.x * v.x + v.y * v.y));}

inline float SquaredMag(const Vector2D& v){    return (v.x * v.x + v.y * v.y);}

struct Origin2D_
{
    const Point2D& operator +(const Vector2D& v)    {        return (static_cast<const Point2D&>(v));    }

    Point2D operator -(const Vector2D& v)    {        return (Point2D(-v.x, -v.y));    }
};

2dVectorPoint.cpp

#include "2dVectorPoint.h"

Origin2D_ Origin2D;

Vector2D& Vector2D::Rotate(float angle)
{
    float s = sinf(angle);
    float c = cosf(angle);

    float nx = c * x - s * y;
    float ny = s * x + c * y;

    x = nx;
    y = ny;

    return (*this);
}
extern Origin2D_ Origin2D;

Code used is adapted from here to save my fingers.

Then we can utilise this to easily compare: we can define rectangle 1 as having P1 and P2 as its bounds and rectangle 2 as having P3 and P4 as its bounds, giving us the following comparison:

if ( P2.y <= P3.y && P1.y >= P4.y && P2.x>= P3.x && P1.x <= P4.x )
{
    return true;
}

This will return a true value for any instance of intersection or for rectangle 1 encompassing rectangle 2 totally.

To only check for intersections just remove the equality check (take all the = out of the above equation), and you will be checking only for intersections. If you have an intersection you could then use linear algebra to evaluate the exact coordinates.

GMasucci
  • 2,747
  • 17
  • 39
  • Thank you so mmuch. It help me to understand what actually I was doing. I will mark the AndreyT answer because it is easy and special for my case work like a charm :) – NoSense Nov 04 '13 at 19:09
  • No problem @NoSense glad to help. That's the best I could ask for, to help understanding, it is worth far more than providing a solution without any understanding. Hope to see you in the future! – GMasucci Nov 05 '13 at 10:12
8

Let's say that a box has a radius X and radius Y (I know it has not but this term is useful here).

You will have:

rect1_x_radius = (x2-x1)/2
rect1_y_radius = (y2-y1)/2

and

rect2_x_radius = (x4-x3)/2
rect2_y_radius = (y4-y3)/2

Now if rect middle points are further away than sum of their radiuses in appropriate direction - they do not collide. Otherwise they do - this hint should suffice.

You should be now able to finish your assignment.

UPDATE:

OK - let's solve it for 1D - later you'll solve it for 2D. Look at this piece of ... art ;-)

enter image description here

You see 2 segments - now some calculations:

rA = (maxA-minA) / 2
rB = (maxB-minB) / 2

midA = minA + rA
midB = minB + rB

mid_dist = |midA - midB|

Now how to check if collision occurs? As I said if sum of 'radiuses' is less than segments' distance - there is no collision:

if ( mid_dist > fabs(rA+rB) )
{
    // no intersection
}
else
{
    // segments intersect
}

Now it is your work to calculate intersection / common part in 1D and 2D. It is up to you now (o ryou can read Andrey's answer).

Here is the same situation but in 2D - two 1D situations:

enter image description here

Artur
  • 6,270
  • 2
  • 23
  • 34
  • 1
    I didn't get it. I need to get the points of intersection, not to check is there any intersection... – NoSense Nov 03 '13 at 13:15
  • @NoSense: Use easier example - work on your problem in 1D first - imagine 2 vectors on X axis - calculate their 'radiuses'((end-start)/2) and both vectors middle points. If distance between middle points is bigger than sum of radiuses they do not collide. OK? Let me know if that is clear - I do not want to provide you with full solution. – Artur Nov 03 '13 at 13:21
  • 1
    I still can't get your idea. I know how to check is there an intersection; I want to know how to get the points... – NoSense Nov 03 '13 at 13:55
  • sorry :(, maybe I am stupid, but can't understand how .to use that...thanks for the help anyway – NoSense Nov 03 '13 at 17:07
  • @NoSense: Look at the picture - now (rA+rB) < mid_dist right? It means there is no intersection. If you now slowly move segments closer mid_dist will slowly approach (rA+rB) value. If they are equal - segments touch each other. When you keep moving them in the same direction mid_dits starts to be < than (rA+rB) - 'full' intersection. Use Anrey's answer to get exact intersection points. I've just shown 1D solution but it is the same approach for 2D - you solve it separately for each axis. – Artur Nov 03 '13 at 17:11
3

You can deal with the x and y direction separately.

Assume that x1 <= x3 (the first box is at least as far to the left as the second). Then, there is overlap if and only if x1 <= x3 <= x2.

Similarly, assume y1 <= y3 (the first box is at least as far to the bottom as the second). Then, there is overlap if and only if y1 <= y3 <= y2.

If there is overlap in both directions, there is a rectangle overlapping. You can find the coordinates by sorting the x and y coordinates and selecting the middle two.

In pseudocode:

if (((x1 <= x3 && x3 <= x2) || (x3 <= x1 && x1 <= x4)) // x-overlap
    &&
    ((y1 <= y3 && y3 <= y2) || (y3 <= y1 && y1 <= y4)) // y-overlap
) {
    int[] xs = {x1, x2, x3, x4};
    int[] ys = {y1, y2, y3, y4};
    sort(xs);
    sort(ys);

    // bottom-left: xs[1], ys[1]
    // top-right:   xs[2], ys[2]
}
Vincent van der Weele
  • 12,311
  • 1
  • 28
  • 58
  • Ok, thanks, this maybe is a solution, but I have to check it is that always work. – NoSense Nov 03 '13 at 13:26
  • @AndreyT I'm not quite sure if I gotyour point. If `x1 <= x3` and `x2 > x4`, the rectangles may still intersect, right? – Vincent van der Weele Nov 03 '13 at 16:13
  • @Heuster: Sotrry, I mixed up the variables. If the initial rectangles are normalized, then the condition is excessive. In order to check that two rectangles intersect all that's needed is `x1 < x4 && x3 < x2 && y1 < y4 && y3 < y2`. That's it. (I used strict inequalities to exclude touching rectangles.) – AnT Nov 03 '13 at 16:32
2

Just in case a straightforward C# solution would suit anyone:

public struct Rectangle
{
    public double Left { get; }
    public double Top { get; }
    public double Width { get; }
    public double Height { get; }
    public double Right => Left + Width;
    public double Bottom => Top + Height;
    public static Rectangle Empty { get; } = new Rectangle(0, 0, 0, 0);

    public Rectangle(double left, double top, double width, double height)
    {
        Left = left;
        Top = top;
        Width = width;
        Height = height;
    }

    public static bool RectanglesIntersect(Rectangle rectangle1, Rectangle rectangle2)
    {
        rectangle1 = rectangle1.Normalize();
        rectangle2 = rectangle2.Normalize();

        if (rectangle2.Left >= rectangle1.Right)
            return false;
        if (rectangle2.Right <= rectangle1.Left)
            return false;

        if (rectangle2.Top >= rectangle1.Bottom)
            return false;
        if (rectangle2.Bottom <= rectangle1.Top)
            return false;

        return true;
    }

    public static Rectangle GetIntersection(Rectangle rectangle1, Rectangle rectangle2)
    {
        rectangle1 = rectangle1.Normalize();
        rectangle2 = rectangle2.Normalize();

        if (rectangle1.IntersectsWith(rectangle2))
        {
            double left = Math.Max(rectangle1.Left, rectangle2.Left);
            double width = Math.Min(rectangle1.Right, rectangle2.Right) - left;
            double top = Math.Max(rectangle1.Top, rectangle2.Top);
            double height = Math.Min(rectangle1.Bottom, rectangle2.Bottom) - top;

            return new Rectangle(left, top, width, height);
        }

        return Empty;
    }

    public Rectangle GetIntersection(Rectangle rectangle)
    {
        return GetIntersection(this, rectangle);
    }

    public bool IntersectsWith(Rectangle rectangle)
    {
        return RectanglesIntersect(this, rectangle);
    }

    public Rectangle NormalizeWidth()
    {
        if (Width >= 0)
            return this;
        Rectangle result = new Rectangle(Left + Width, Top, -Width, Height);
        return result;
    }

    public Rectangle NormalizeHeight()
    {
        if (Height >= 0)
            return this;
        Rectangle result = new Rectangle(Left, Top + Height, Width, -Height);
        return result;
    }

    public Rectangle Normalize()
    {
        Rectangle result = NormalizeWidth().NormalizeHeight();
        return result;
    }
}
pzrq
  • 1,167
  • 1
  • 14
  • 16
Phil Brook
  • 21
  • 2