jburn7
jburn7

Reputation: 125

How to rotate points about a specific origin?

I'm working on rotating the vertices of my object around a point located on the object that's not necessarily its center. I followed this tutorial pretty closely and got the vertices to keep their same proportions, i.e. the shape that they create does rotate about the given point, however the amount by which it rotates seems arbitrary. I'll explain in the code and the screenshots. I'm using SFML, but I'll explain the sf:: namespaces in the comments where they're used for those who need it. Anyways, here's my main file that shows the problem:

int _tmain(int argc, _TCHAR* argv[]){
sf::RenderWindow window(sf::VideoMode(500, 500, 32), "Animation");

//sf::vertexarray is a list of POINTS on the screen, their position is determined with a sf::vector
sf::VertexArray vertices;

//arrange 6 points in a shape
vertices.setPrimitiveType(sf::PrimitiveType::Points);
//bottom middle
vertices.append(sf::Vector2f(200, 200));
//left bottom edge
vertices.append(sf::Vertex(sf::Vector2f(195, 195)));
//left top edge
vertices.append(sf::Vertex(sf::Vector2f(195, 175)));
//top middle
vertices.append(sf::Vertex(sf::Vector2f(200, 170)));
//top right corner
vertices.append(sf::Vertex(sf::Vector2f(205, 175)));
//bottom right corner
vertices.append(sf::Vertex(sf::Vector2f(205, 195)));

//rotation is the shape's rotation... 0 means it's straight up, and it rotates clockwise with positive rotation
float rotation = 0;
//used later to pause the program
bool keypressed = false;

while(window.isOpen()){
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)){
        window.close();
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
        //this SHOULD rotate the shape by 10 degrees, however it rotates it by like 150-ish
        //why does this not work as expected?
        rotation = 10;
        //this transformation part works fine, it simply moves the points to center them on the origin, rotates them using a rotation matrix, and moves
        //them back by their offset
        for(int i = 1; i < vertices.getVertexCount(); i++){
            //translate current point so that the origin is centered
            vertices[i].position -= vertices[0].position;

            //rotate points
            //I'm guessing this is the part where the rotation value is screwing up?
            //because rotation is simply theta in a regular trig function, so the shape should only rotate 10 degrees
            float newPosX = vertices[i].position.x * cosf(rotation) + vertices[i].position.y * sinf(rotation);
            float newPosY = -vertices[i].position.x * sinf(rotation) + vertices[i].position.y * cosf(rotation);

            //translate points back
            vertices[i].position.x = newPosX + vertices[0].position.x;
            vertices[i].position.y = newPosY + vertices[0].position.y;
        }
        keypressed = true;
    }

    //draw
    window.clear();
    window.draw(vertices);
    window.display();
    if(keypressed == true){
        //breakpoint here so the points only rotate once
        system("pause");
    }
}
return 0;

}

Also, here are the screenshots showing what I mean. Sorry it's a bit small. The left side shows the shape created at the start of the program, with the green point being the origin. The right side shows the shape after the rotation for loop is called, with the red points showing where the shape actually rotates to (definitely not 10 degrees) versus the blue dots, which are roughly where I expected the shape to be at, around 10 degrees.

tl;dr: Using a rotation matrix, the points being rotated keep their proportions, but the amount by which they are rotating is totally arbitrary. Any suggestions/improvements?

enter image description here

Upvotes: 1

Views: 2208

Answers (1)

Maxime Alvarez
Maxime Alvarez

Reputation: 180

Using the SFML, you first create a transformation :

sf::Transform rotation;
rotation.rotate(10, centerOfRotationX, centerOfRotationY);

Then you apply this transformation to the position of each vertex :

sf::Vector2f positionAfterRotation = rotation.transformPoint(positionBeforeRotation);

Sources : sf::Transform::rotate and sf::Transform::transformPoint.

Upvotes: 2

Related Questions