Wednesday, 8 August 2012

Axis Aligned Rectangles

So, what are you looking at in that clip?

Exactly what the title of this post is eluding to, a Rectangle structure that can be used to detect collision like the one we have in XNA. I have kept it Axis Aligned just like the intrinsic XNA one. If you don’t know what I mean by Axis Aligned, then have a Google or a Bing for it, it basically means that the collision detection is done based on the rectangle not being rotated.

In the clip we see RED rectangles, these show up when two rectangles intersect, a BLUE rectangle is the Union rectangle that holds both of the colliding rectangles, the GREEN rectangle is shown when a rectangle is Contained by another and the WHITE rectangle is the Intersect rectangle.

I have been working on trying to get a C++ framework together so I can start writing about some GPU elements, ad realize that I am skimping on the code snippets, so, here is how I have constructed the RCRectangle structure.

My header file looks like this:

struct RCRectangle
{
protected:
public:

    float X;
    float Y;
    float Width;
    float Height;

    DECLDIR RCRectangle(void);
    DECLDIR RCRectangle(XMFLOAT4 dimensions);
    DECLDIR virtual ~RCRectangle(void);


    DECLDIR static RCRectangle Intersect(RCRectangle rectangle1, RCRectangle rectangle2);
    DECLDIR static void Intersect(RCRectangle rectangle1, RCRectangle rectangle2, OUT RCRectangle rectangle3);

    DECLDIR virtual bool Intersects(RCRectangle rectangle);

    DECLDIR virtual bool Contains(RCRectangle rectangle);

    DECLDIR static RCRectangle Union(RCRectangle rectangle1, RCRectangle rectangle2);
    DECLDIR static void Union(RCRectangle rectangle1,RCRectangle rectangle2, OUT RCRectangle rectangle3);
    
};

So, we have an X and Y to give us our top left corner and a Width and a Height to give us the opposing corner.

I have also put in the same methods we have in XNA, so Intersect to get the rectangle where the two rectangles overlap, Intersects to detect rectangle intersection, Contains for when a rectangle contains another and Union used to create a rectangle that will contain the two rectangles.

The RCRectangle.cpp file has the function bodies and they look like this:

RCRectangle::RCRectangle(void)
{

}

RCRectangle::RCRectangle(XMFLOAT4  dimensions)
{
    X = dimensions.x;
    Y = dimensions.y;
    Width = dimensions.z;
    Height = dimensions.w;
}

RCRectangle::~RCRectangle(void)
{

}

void RCRectangle::Intersect(RCRectangle rectangle1, RCRectangle rectangle2,OUT RCRectangle rectangleOut)
{
    if(rectangle1.Intersects(rectangle2))
    {
        float x,y,w,h = 0;

        if(rectangle1.X >= rectangle2.X)
            x = rectangle1.X;
        else
            x = rectangle2.X;

        if(rectangle1.Y >= rectangle2.Y)
            y = rectangle1.Y;
        else
            y = rectangle2.Y;

        if(rectangle1.X + rectangle1.Width <= rectangle2.X + rectangle2.Width)
            w = (rectangle1.X + rectangle1.Width) - x;
        else
            w = (rectangle2.X + rectangle2.Width) - x;

        if(rectangle1.Y + rectangle1.Height <= rectangle2.Y + rectangle2.Height)
            h = (rectangle1.Y + rectangle1.Height) - y;
        else
            h = (rectangle2.Y + rectangle2.Height) - y;

        rectangleOut = RCRectangle(XMFLOAT4(x,y,w,h));
    }
}
RCRectangle RCRectangle::Intersect(RCRectangle rectangle1, RCRectangle rectangle2)
{
    RCRectangle retVal(XMFLOAT4(0,0,0,0));

    if(rectangle1.Intersects(rectangle2))
    {
        float x,y,w,h = 0;

        if(rectangle1.X >= rectangle2.X)
            x = rectangle1.X;
        else
            x = rectangle2.X;

        if(rectangle1.Y >= rectangle2.Y)
            y = rectangle1.Y;
        else
            y = rectangle2.Y;

        if(rectangle1.X + rectangle1.Width <= rectangle2.X + rectangle2.Width)
            w = (rectangle1.X + rectangle1.Width) - x;
        else
            w = (rectangle2.X + rectangle2.Width) - x;

        if(rectangle1.Y + rectangle1.Height <= rectangle2.Y + rectangle2.Height)
            h = (rectangle1.Y + rectangle1.Height) - y;
        else
            h = (rectangle2.Y + rectangle2.Height) - y;

        retVal = RCRectangle(XMFLOAT4(x,y,w,h));
    }

    return retVal;
}

bool RCRectangle::Intersects(RCRectangle rectangle)
{
    bool retVal = true;

    // AA Check.
    if(
        X > rectangle.X + rectangle.Width ||
        Y > rectangle.Y + rectangle.Height ||
        X + Width < rectangle.X ||
        Y + Height < rectangle.Y)
    {
        // Can't possibly have overlap
        retVal = false;
    }
    else
    {
        retVal = true;
    }


    return retVal;
}

bool RCRectangle::Contains(RCRectangle rectangle)
{
    bool retVal = false;

    if(X <= rectangle.X && X + Width >= rectangle.X + rectangle.Width &&
        Y <= rectangle.Y && Y + Height >= rectangle.Y + rectangle.Height)
        retVal = true;

    return retVal;
}

RCRectangle RCRectangle::Union(RCRectangle rectangle1,RCRectangle rectangle2)
{
    float x = 0 ,y = 0,w = 0,h = 0;

    if(rectangle1.X <= rectangle2.X)
        x = rectangle1.X;
    else
        x = rectangle2.X;

    if(rectangle1.Y <= rectangle2.Y)
        y = rectangle1.Y;
    else
        y = rectangle2.Y;

    if(rectangle1.X + rectangle1.Width >= rectangle2.X + rectangle2.Width)
        w = (rectangle1.X + rectangle1.Width) - x;
    else
        w = (rectangle2.X + rectangle2.Width) - x;

    if(rectangle1.Y + rectangle1.Height >= rectangle2.Y + rectangle2.Height)
        h = (rectangle1.Y + rectangle1.Height) - y;
    else
        h = (rectangle2.Y + rectangle2.Height) - y;

    return RCRectangle(XMFLOAT4(x,y,w,h));
}

void RCRectangle::Union(RCRectangle rectangle1,RCRectangle rectangle2, OUT RCRectangle rectangle3)
{
    float x = 0 ,y = 0,w = 0,h = 0;

    if(rectangle1.X <= rectangle2.X)
        x = rectangle1.X;
    else
        x = rectangle2.X;

    if(rectangle1.Y <= rectangle2.Y)
        y = rectangle1.Y;
    else
        y = rectangle2.Y;

    if(rectangle1.X + rectangle1.Width >= rectangle2.X + rectangle2.Width)
        w = (rectangle1.X + rectangle1.Width) - x;
    else
        w = (rectangle2.X + rectangle2.Width) - x;

    if(rectangle1.Y + rectangle1.Height >= rectangle2.Y + rectangle2.Height)
        h = (rectangle1.Y + rectangle1.Height) - y;
    else
        h = (rectangle2.Y + rectangle2.Height) - y;

    rectangle3 = RCRectangle(XMFLOAT4(x,y,w,h));
}

 

If you are wondering what the DELDIR is, it’s a macro I am using so the methods can be accessed from out side the library when included in a project and it looks like this:

#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif

Hope you find this post useful, as ever C&C are welcome :D

2 comments:

  1. Heyas,
    Not sure if intentional but c++ doesn't really have the same class/struct distinction that c# does. structs are just classes with everything public by default .

    m<

    ReplyDelete
    Replies
    1. Nope, didn't know that :S Thanks though, I do now :D

      Delete