0

Given two simple, rectangles:

class Rectangle
{
    int x;
    int y;
    int width;
    int height;
}

Rectangle a;
Rectangle b;

and the following enumeration:

[Flags]
enum Edges
{
    None,
    Top,
    Bottom,
    Left,
    Right,
    Inside,
}

What is the quickest way to detect the edges on rectangle a which are collided with by rectangle b?

Edges e = EdgeDetect(a, b);
6
  • 1
    quick = little code, or, quick = fast? also: is x,y a corner or the middle point? Commented Nov 29, 2011 at 8:37
  • 1
    What's an inside edge? Commented Nov 29, 2011 at 8:45
  • 2
    @Rob: SO is not "rent-a-coder", so I am still struggling if I should vote this question down . But if you provide us with your own implementation, the community will happily look at your code and make some suggestions how to improve it. Commented Nov 29, 2011 at 8:52
  • @Doc: I suspect it means that b is entirely enclosed by a (without any edges directly intersecting). Commented Nov 29, 2011 at 8:57
  • 1
    @Doc, instead it's number (also known as reputation) hooing Commented Nov 29, 2011 at 11:06

2 Answers 2

2
public Edges DetectEdge(Rect A, Rect B) { 
   rectC = rectA.Intersect(rectB);
    if(rectC.IsEmpty) return Edges.None;
    Edge edge = Edges.Inside;
    if(rectA.X+rectA.Width == rectB.X || rectA.X == rectB.X){
     edge = Edges.Left;
    }
    if(rectA.Y+rectA.Height == rectB.Y || rectA.Y == rectB.Y){
     edge = edge | Edges.Top;
    }
    if(rectA.X  == rectB.X + rectB.Width 
         || rectA.X + rectA.Width == rectB.X + rectB.Width){
     edge = edge | Edges.Right;
    }
    if(rectA.Y == rectB.Y + rectB.Heigth 
         || rectA.Y + rectA.Height == rectB.Y + rectB.Height){
     edge = edge | Edges.Bottom;
    }
    return edge;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Your code only detect one edge intersection. Instead of returning an Edge, you should bitwise or in each if.
I assumed, he needs another rectA colliding to rectB from outside. Modified the code as per suggested
1

First of all, you have to defines explicitly values of your enum in order to have flags working correctly. In you case Left == Top + Bottom + None. Here is a possible declaration :

[Flags]
public enum Edges
{
    None = 0,
    Top = 1,
    Bottom = 2,
    Left = 4,
    Right = 8,
    Identical = Top + Bottom + Left + Right,
    Inside = 16,
    Covers = 32
}

Next, a possible implementation of edge collision detection. Note that I use the builtin System.Drawing.Rectangle instead of rewriting the class. The immediate advantage is the availability of the Intersect method. :

public static Edges DetectEdgesCollision(Rectangle a, Rectangle b)
{
    var result = Edges.None;

    if (a == b) return Edges.Identical;
    b.Intersect(a);
    if (b.IsEmpty) return Edges.None;
    if (a == b) return Edges.Covers;


    if (a.Top == b.Top && (a.Right >= b.Right && a.Left<=b.Left )) 
        result |= Edges.Top;
    if (a.Bottom == b.Bottom && (a.Right >= b.Right && a.Left<=b.Left ))
        result |= Edges.Bottom;
    if (a.Left == b.Left && (a.Bottom >= b.Bottom && a.Top <= b.Top)) 
        result |= Edges.Left;
    if (a.Right == b.Right && (a.Bottom >= b.Bottom && a.Top <= b.Top)) 
        result |= Edges.Right;


    return result == Edges.None ? Edges.Inside : result;
}

Here is a set of tests that validates this implementation :

    [TestMethod]
    public void RectDoesNotIntersect()
    {
        var a = new Rectangle(0, 0, 10, 10);
        var b = new Rectangle(20, 20, 10, 10);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.None, result);
    }


    [TestMethod]
    public void RectAreNested()
    {
        var a = new Rectangle(0, 0, 30,30);
        var b = new Rectangle(10, 10, 10, 10);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Inside, result);
    }      
    [TestMethod]
    public void RectCollidesOnTopAndLeft()
    {
        var a = new Rectangle(10, 10, 10, 10);
        var b = new Rectangle(0, 0, 10, 10);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Left | Edges.Top, result);
    }     
    [TestMethod]
    public void RectCollidesOnBottom()
    {
        var a = new Rectangle(0, 0, 20, 20);
        var b = new Rectangle(10, 10, 5, 50);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Bottom , result);
    }        

    [TestMethod]
    public void RectAreIdenticals()
    {
        var a = new Rectangle(10, 10, 10, 10);
        var b = new Rectangle(10, 10, 10, 10);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Identical, result);
    }  
    [TestMethod]
    public void RectBCoversA()
    {
        var a = new Rectangle(10, 10, 10, 10);
        var b = new Rectangle(0, 0, 30, 30);

        var result = Program.DetectEdgesCollision(a, b);

        Assert.AreEqual<Edges>(Edges.Covers, result);
    }     

2 Comments

Fantastic response Steve :) - This works really well. The only minor issue is that Identical is returned if Rectangle B is larger than rectangle A and completely covers it. Maybe it should be 'Covers' or 'Engulfs' rather than 'Identical'? Thanks.
You are right, I updated the code. A new enum value Covered is defined, the DetectEdge methode is slightly changed to detect identical first, then covers, then per edge. A new Test has also been added.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.