Page 1 of 3

Calculating vertices of a rotated rectangle

Posted: Wed Sep 23, 2009 6:55 pm
by short
Hey guys, I am trying to calculate the vertices of a rotated rectangle (2D).

It's easy enough if the rectangle has not been rotated, I figured that part out.

If the rectangle has been rotated, I thought of two possible ways to calculate the vertices.
1) Figure out how to transform the vertices from local/object/model space (the ones I figured out below) to world space. I honestly have no clue, and if it is the best way then I feel like I would learn a lot from it if I could figure it out...

2) Use trig to somehow figure out where the endpoints of the rectangle are relative to the position of the rectangle in world space. This has been the way I have been trying to do up until now, I just haven't figured out how.

Here's the function that calculates the vertices thus far, thanks for any help :oops:

Code: Select all

void Rect::calculateVertices()
{
    if(m_orientation == 0) // if no rotation
    {
        setVertices(
        &Vertex( (m_position.x - (m_width / 2) * m_scaleX), (m_position.y + (m_height / 2) * m_scaleY), m_position.z), 
        &Vertex( (m_position.x + (m_width / 2) * m_scaleX), (m_position.y + (m_height / 2) * m_scaleY), m_position.z),
        &Vertex( (m_position.x + (m_width / 2) * m_scaleX), (m_position.y - (m_height / 2) * m_scaleY), m_position.z),
        &Vertex( (m_position.x - (m_width / 2) * m_scaleX), (m_position.y - (m_height / 2) * m_scaleY), m_position.z) );
    }
    else
    {
        // if the rectangle has been rotated..
    }

    //GLfloat theta = RAD_TO_DEG( atan( ((m_width/2) * m_scaleX) / ((m_height / 2) * m_scaleY) ) );
    //LOG->writeLn(&theta);

}

Re: Calculating vertices of a rotated rectangle

Posted: Wed Sep 23, 2009 9:20 pm
by short
Solved.

I'll go ahead and post my solution in case it may be helpful to others. ;)

Code: Select all

void Rect::calculateVertices()
{
    if(m_orientation == 0) // if no rotation
    {
        setVertices(
        &Vertex( (m_position.x - (m_width / 2) * m_scaleX), (m_position.y + (m_height / 2) * m_scaleY), m_position.z), 
        &Vertex( (m_position.x + (m_width / 2) * m_scaleX), (m_position.y + (m_height / 2) * m_scaleY), m_position.z),
        &Vertex( (m_position.x + (m_width / 2) * m_scaleX), (m_position.y - (m_height / 2) * m_scaleY), m_position.z),
        &Vertex( (m_position.x - (m_width / 2) * m_scaleX), (m_position.y - (m_height / 2) * m_scaleY), m_position.z) );
    }
    else
    {
        Vertex TL = Vertex( 
            ((m_position.x - (m_width / 2) * m_scaleX) * cos(DEG_TO_RAD(m_orientation))) - 
            ((m_position.y + (m_height / 2) * m_scaleY) * sin(DEG_TO_RAD(m_orientation))),
            
            ((m_position.x - (m_width / 2) * m_scaleX) * sin(DEG_TO_RAD(m_orientation))) +
            ((m_position.y + (m_height / 2) * m_scaleY) * cos(DEG_TO_RAD(m_orientation)))
            , m_position.z);

        Vertex TR = Vertex( 
            ((m_position.x + (m_width / 2) * m_scaleX) * cos(DEG_TO_RAD(m_orientation))) - 
            ((m_position.y + (m_height / 2) * m_scaleY) * sin(DEG_TO_RAD(m_orientation))),
            
            ((m_position.x + (m_width / 2) * m_scaleX) * sin(DEG_TO_RAD(m_orientation))) +
            ((m_position.y + (m_height / 2) * m_scaleY) * cos(DEG_TO_RAD(m_orientation)))
            , m_position.z);

        Vertex BR = Vertex( 
            ((m_position.x + (m_width / 2) * m_scaleX) * cos(DEG_TO_RAD(m_orientation))) - 
            ((m_position.y - (m_height / 2) * m_scaleY) * sin(DEG_TO_RAD(m_orientation))),
            
            ((m_position.x + (m_width / 2) * m_scaleX) * sin(DEG_TO_RAD(m_orientation))) +
            ((m_position.y - (m_height / 2) * m_scaleY) * cos(DEG_TO_RAD(m_orientation)))
            , m_position.z);

        Vertex BL = Vertex( 
            ((m_position.x - (m_width / 2) * m_scaleX) * cos(DEG_TO_RAD(m_orientation))) - 
            ((m_position.y - (m_height / 2) * m_scaleY) * sin(DEG_TO_RAD(m_orientation))),
            
            ((m_position.x - (m_width / 2) * m_scaleX) * sin(DEG_TO_RAD(m_orientation))) +
            ((m_position.y - (m_height / 2) * m_scaleY) * cos(DEG_TO_RAD(m_orientation)))
            , m_position.z);


        setVertices( &TL, &TR, &BR, &BL );

    }
}

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Wed Sep 23, 2009 9:30 pm
by trufun202
Wow, what a coincidence. A buddy of mine at work was trying to find the exact same thing for a WPF app that he's working on.

We came up with a way around it, so we didn't have to worry about the verts, but it's cool to see it solved with trig.

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Wed Sep 23, 2009 11:16 pm
by short
trufun202 wrote:Wow, what a coincidence. A buddy of mine at work was trying to find the exact same thing for a WPF app that he's working on.

We came up with a way around it, so we didn't have to worry about the verts, but it's cool to see it solved with trig.
Care to elaborate on how you guys did it?

Re: Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 11:08 am
by MarauderIIC
short0014 wrote:Solved.

I'll go ahead and post my solution in case it may be helpful to others. ;)

Code: Select all

void Rect::calculateVertices()
{
    if(m_orientation == 0) // if no rotation
    {
        setVertices(
        &Vertex( (m_position.x - (m_width / 2) * m_scaleX), (m_position.y + (m_height / 2) * m_scaleY), m_position.z), 
        &Vertex( (m_position.x + (m_width / 2) * m_scaleX), (m_position.y + (m_height / 2) * m_scaleY), m_position.z),
        &Vertex( (m_position.x + (m_width / 2) * m_scaleX), (m_position.y - (m_height / 2) * m_scaleY), m_position.z),
        &Vertex( (m_position.x - (m_width / 2) * m_scaleX), (m_position.y - (m_height / 2) * m_scaleY), m_position.z) );
    }
    else
    {
        Vertex TL = Vertex( 
            ((m_position.x - (m_width / 2) * m_scaleX) * cos(DEG_TO_RAD(m_orientation))) - 
            ((m_position.y + (m_height / 2) * m_scaleY) * sin(DEG_TO_RAD(m_orientation))),
            
            ((m_position.x - (m_width / 2) * m_scaleX) * sin(DEG_TO_RAD(m_orientation))) +
            ((m_position.y + (m_height / 2) * m_scaleY) * cos(DEG_TO_RAD(m_orientation)))
            , m_position.z);

        Vertex TR = Vertex( 
            ((m_position.x + (m_width / 2) * m_scaleX) * cos(DEG_TO_RAD(m_orientation))) - 
            ((m_position.y + (m_height / 2) * m_scaleY) * sin(DEG_TO_RAD(m_orientation))),
            
            ((m_position.x + (m_width / 2) * m_scaleX) * sin(DEG_TO_RAD(m_orientation))) +
            ((m_position.y + (m_height / 2) * m_scaleY) * cos(DEG_TO_RAD(m_orientation)))
            , m_position.z);

        Vertex BR = Vertex( 
            ((m_position.x + (m_width / 2) * m_scaleX) * cos(DEG_TO_RAD(m_orientation))) - 
            ((m_position.y - (m_height / 2) * m_scaleY) * sin(DEG_TO_RAD(m_orientation))),
            
            ((m_position.x + (m_width / 2) * m_scaleX) * sin(DEG_TO_RAD(m_orientation))) +
            ((m_position.y - (m_height / 2) * m_scaleY) * cos(DEG_TO_RAD(m_orientation)))
            , m_position.z);

        Vertex BL = Vertex( 
            ((m_position.x - (m_width / 2) * m_scaleX) * cos(DEG_TO_RAD(m_orientation))) - 
            ((m_position.y - (m_height / 2) * m_scaleY) * sin(DEG_TO_RAD(m_orientation))),
            
            ((m_position.x - (m_width / 2) * m_scaleX) * sin(DEG_TO_RAD(m_orientation))) +
            ((m_position.y - (m_height / 2) * m_scaleY) * cos(DEG_TO_RAD(m_orientation)))
            , m_position.z);


        setVertices( &TL, &TR, &BR, &BL );

    }
}
I know this is a bit off-topic, but you should probably..

Code: Select all

void Rect::calculateVertices()
{
    //Let the compiler do some copy-pasting or other fun const optimizations.
    //Also, easier to read.
    const int WIDTH_SCALE = (m_width / 2) * m_scaleX;
    const int HEIGHT_SCALE = (m_height / 2) * m_scaleY;

    const int LEFT = m_position.x - WIDTH_SCALE;
    const int RIGHT = m_position.x + WIDTH_SCALE;

    const int TOP  = m_position.y + HEIGHT_SCALE;
    const int BOTTOM = m_position.y - HEIGHT_SCALE;

    const int RADIANS = DEG_TO_RAD(m_orientation);

    if(m_orientation == 0) // if no rotation
    {
        setVertices(
        &Vertex(LEFT, TOP, m_position.z), 
        &Vertex(RIGHT, TOP, m_position.z),
        &Vertex(RIGHT, BOTTOM, m_position.z),
        &Vertex(LEFT, BOTTOM, m_position.z) );
    }
    else
    {
        Vertex TL = Vertex( 
            (LEFT * cos(RADIANS)) - 
            (TOP * sin(RADIANS)),
            
            (LEFT * sin(RADIANS)) +
            (TOP * cos(RADIANS))
            , m_position.z);

        Vertex TR = Vertex( 
            (RIGHT * cos(RADIANS)) - 
            (TOP * sin(RADIANS)),
            
            (RIGHT * sin(RADIANS)) +
            (TOP * cos(RADIANS))
            , m_position.z);

        Vertex BR = Vertex( 
            (RIGHT * cos(RADIANS)) - 
            (BOTTOM * sin(RADIANS)),
            
            (RIGHT * sin(RADIANS)) +
            (BOTTOM * cos(RADIANS))
            , m_position.z);

        Vertex BL = Vertex( 
            (LEFT * cos(RADIANS)) - 
            (BOTTOM * sin(RADIANS)),
            
            (LEFT * sin(RADIANS)) +
            (BOTTOM * cos(RADIANS))
            , m_position.z);


        setVertices( &TL, &TR, &BR, &BL );

    }
Isn't that better?

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 11:25 am
by short
Ah, yes it is. Sometimes compiler optimizations I forget about. So, thanks :)

And yes, it's much better lol

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 11:31 am
by qpHalcy0n
Calculate sin and cos once. Those two functions are costlier than anything in that whole shabang there.

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 11:35 am
by trufun202
short0014 wrote:
trufun202 wrote:Wow, what a coincidence. A buddy of mine at work was trying to find the exact same thing for a WPF app that he's working on.

We came up with a way around it, so we didn't have to worry about the verts, but it's cool to see it solved with trig.
Care to elaborate on how you guys did it?
Well, we basically have an object (such as a rectangle) that is being rotated. Then we wanted to draw an outline around that object as it rotates - showing that the object is selected.

Before we introduced rotation, were were drawing the outline by getting the Top and Left of the object, along with it's Width and Height. But, when rotated, the canvas acts as a bounding box, and thus the Top and Left did not change. To solve this, we first thought that we'd have to calculate the vertices of the object after rotation. However, we just placed the outline on another canvas with a higher ZIndex, and rotated that canvas along with the object.

But, this was all in WPF...not sure how that's going to translate into your implementation...

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 11:57 am
by short
Ok, for anyone in using this I'll post the fastest version I can come up with:

Code: Select all

void Rect::calculateVertices()
{
    //Let the compiler do some copy-pasting or other fun const optimizations.
    //Also, easier to read.
    const GLfloat WIDTH_SCALE = (m_width / 2) * m_scaleX;
    const GLfloat HEIGHT_SCALE = (m_height / 2) * m_scaleY;

    const GLfloat LEFT = m_position.x - WIDTH_SCALE;
    const GLfloat RIGHT = m_position.x + WIDTH_SCALE;

    const GLfloat TOP  = m_position.y + HEIGHT_SCALE;
    const GLfloat BOTTOM = m_position.y - HEIGHT_SCALE;

    if(m_orientation == 0) // if no rotation
    {
        setVertices(
        &Vertex( LEFT, TOP, m_position.z), 
        &Vertex( RIGHT, TOP, m_position.z),
        &Vertex( RIGHT, BOTTOM, m_position.z),
        &Vertex( LEFT, BOTTOM, m_position.z) );
    }
    else
    {
        const GLfloat radians = (GLfloat)DEG_TO_RAD(m_orientation);
        const GLfloat cosn = (GLfloat)cos(radians);
        const GLfloat sinn = (GLfloat)sin(radians);

        Vertex TL = Vertex( (LEFT  * cosn) - (TOP * sinn)   , (LEFT  * sinn) + (TOP *    cosn), m_position.z );
        Vertex TR = Vertex( (RIGHT * cosn) - (TOP * sinn)   , (RIGHT * sinn) + (TOP *    cosn), m_position.z );
        Vertex BR = Vertex( (RIGHT * cosn) - (BOTTOM * sinn), (RIGHT * sinn) + (BOTTOM * cosn), m_position.z );
        Vertex BL = Vertex( (LEFT  * cosn) - (BOTTOM * sinn), (LEFT  * sinn) + (BOTTOM * cosn), m_position.z);

        setVertices( &TL, &TR, &BR, &BL );

    }
}
Marauder, I'm curious, do you know anything about how by making a variable const vs nonconstant the compiler can optimize it?

I'm very curious about this if you would care to explain a bit.

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 12:05 pm
by Falco Girgis
Your code looks pretty good. I'm assuming that you needed this to actually rotate something to use with your OBB separating axis collision? So did you get it working with axis-aligned?

As for constant optimization, I really can't speak for x86, but many processors and architectures have special registers for frequently used constants. The compiler probably sees that it is a good idea to throw something defined as a const into one of these special registers. Remember, accessing a register is much faster than RAM.

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 12:35 pm
by short
GyroVorbis wrote:Your code looks pretty good. I'm assuming that you needed this to actually rotate something to use with your OBB separating axis collision? So did you get it working with axis-aligned?

As for constant optimization, I really can't speak for x86, but many processors and architectures have special registers for frequently used constants. The compiler probably sees that it is a good idea to throw something defined as a const into one of these special registers. Remember, accessing a register is much faster than RAM.
Yeah, I did need this for my separating axis collision. When I was working on implementing what you told me about the theorem I ran into the problem that I didn't know where the corners of the rectangles were. The only way I was getting the rectangle was to translate and draw the rectangle as normal.

This way, I never translate to draw the rectangle, I just calculate the new vertices and draw the rectangle with no translation. I honestly have no idea what kind of performance hit it will be calculating the rotated vertices vs just translating and drawing, then translating back. I think the translation method would be faster, but for now this is working great. I may revisit that issue after I get the seperating axis theorem implemented correctly.

.. As for actually implementing the theorem I'm going to work on it tonight after work, I have yet to learn linear algebra so your explanation seems a little bit cryptic to me.

However, I am learning a lot about vectors, what exactly an axis is, how to normalize said axis, and what a "normal vector" is. Maybe by the time I'm done I'll have a head start on all of this going into linear algebra :lol:

Oh, and that makes sense about the compiler using a special register for constants. It's actually very interesting :shock:

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 12:47 pm
by avansc
qp makes a very good point. so much, that if that was going to be called each game loop. i would strongly recommend to pre calculate sin and cos or all trig function.

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 2:00 pm
by MarauderIIC
short0014 wrote:Marauder, I'm curious, do you know anything about how by making a variable const vs nonconstant the compiler can optimize it?
I probably used to. Found these in my bookmarks w/ tags "const optimization" : http://www.mi.uni-koeln.de/c/mirror/www ... c0092.html http://stackoverflow.com/questions/2122 ... ation-in-c http://gotw.ca/gotw/081.htm
qpHalcy0n wrote:Calculate sin and cos once. Those two functions are costlier than anything in that whole shabang there.
Whoops, I wasn't paying attention to the fact that he was doing that =)

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Thu Sep 24, 2009 5:05 pm
by Bakkon
This thread is awesome and I think I see how to modify it to work for any polygon with equal length edges. I definitely need to start playing with OpenGL.

Re: [Solved] Calculating vertices of a rotated rectangle

Posted: Fri Sep 25, 2009 1:55 am
by short
avansc wrote:qp makes a very good point. so much, that if that was going to be called each game loop. i would strongly recommend to pre calculate sin and cos or all trig function.
Well, the way I have it set up is this function is only called upon if something changes (ie setScaleX or setOrientation or setPosition etc...)

I added a way to track the previous rotation, if the rotation has not been changed when this function is called, there is no reason to recalculate sin and cos, so I simply reuse them (they are the only two values of the array).

This is the best way I can think of doing this.
Anyone?

Code: Select all

void Rect::calculateVertices()
{
    const GLfloat WIDTH_SCALE = (m_width / 2) * m_scaleX;
    const GLfloat HEIGHT_SCALE = (m_height / 2) * m_scaleY;

    const GLfloat LEFT = m_position.x - WIDTH_SCALE;
    const GLfloat RIGHT = m_position.x + WIDTH_SCALE;

    const GLfloat TOP  = m_position.y + HEIGHT_SCALE;
    const GLfloat BOTTOM = m_position.y - HEIGHT_SCALE;

    if(m_orientation == 0) // if no rotation
    {
        setVertices(
        &Vertex( LEFT, TOP, m_position.z),
        &Vertex( RIGHT, TOP, m_position.z),
        &Vertex( RIGHT, BOTTOM, m_position.z),
        &Vertex( LEFT, BOTTOM, m_position.z) );
    }
    else
    {
        if(m_prev_orientation != m_orientation) // only calculate sin/cos if orientation has changed.
        {
            const GLfloat radians = (GLfloat)DEG_TO_RAD(m_orientation);
            const GLfloat cosn = (GLfloat)cos(radians);
            const GLfloat sinn = (GLfloat)sin(radians);
            m_pre_trig_calcs[COSN] = cosn;
            m_pre_trig_calcs[SINN] = sinn;
            m_prev_orientation = m_orientation;
        }

        Vertex TL = Vertex( (LEFT  * m_pre_trig_calcs[COSN]) - (TOP * m_pre_trig_calcs[SINN])   , 
            (LEFT  * m_pre_trig_calcs[SINN]) + (TOP *    m_pre_trig_calcs[COSN]), m_position.z );

        Vertex TR = Vertex( (RIGHT * m_pre_trig_calcs[COSN]) - (TOP * m_pre_trig_calcs[SINN])   ,
            (RIGHT * m_pre_trig_calcs[SINN]) + (TOP *    m_pre_trig_calcs[COSN]), m_position.z );

        Vertex BR = Vertex( (RIGHT * m_pre_trig_calcs[COSN]) - (BOTTOM * m_pre_trig_calcs[SINN]),
            (RIGHT * m_pre_trig_calcs[SINN]) + (BOTTOM * m_pre_trig_calcs[COSN]), m_position.z );

        Vertex BL = Vertex( (LEFT  * m_pre_trig_calcs[COSN]) - (BOTTOM * m_pre_trig_calcs[SINN]),
            (LEFT  * m_pre_trig_calcs[SINN]) + (BOTTOM * m_pre_trig_calcs[COSN]), m_position.z);


        setVertices( &TL, &TR, &BR, &BL );

    }
}