Rotating point around point in 2D

Started by
6 comments, last by nobodynews 9 years, 6 months ago

Hello.

Its simple as it sounds, rotating a point around point to simulate clock.

But i got: the point that is supposed to rotate goes away from the point that it is supposed to rotate around and i don't know where i made the mistake.

sf::Vector2f is just a vector of two points, x and y.

Also main for sfml 2.0 for example.


void Rotate(sf::Vector2f & p, double angle, sf::Vector2f r)
{
    double pi = 3.14159;
    float s = sin(angle);
    float c = cos(angle);

    r.x -= p.x;
    r.y -= p.y;

    p.x += r.x * c - r.y * s;
    p.y += r.x * s + r.y * c;
}

int main()
{
    sf::RenderWindow win;
    sf::VideoMode vidMod(800, 600, 32);
    win.create(vidMod, "hello", sf::Style::Default);
    win.setFramerateLimit(60);

    sf::VertexArray vaL;
    vaL.setPrimitiveType(sf::Lines);
    vaL.append(sf::Vertex(sf::Vector2f(400, 300)));
    vaL.append(sf::Vertex(sf::Vector2f(600, 300)));
    double angle = 90;
    bool done = false;
    while (done == false)
    {
        win.clear();

        sf::Event event;
        while (win.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                done = true;
                break;
            default:
                break;
            }
        }
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::R))
            Rotate(vaL[1].position, angle, vaL[0].position);

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
        {//Reset data to old
            vaL[0] = (sf::Vertex(sf::Vector2f(400, 300)));
            vaL[1] = (sf::Vertex(sf::Vector2f(600, 300)));
        }

        win.draw(vaL);

        win.display();
    }

    return 0;
};
Advertisement
You posted entirely too much code. You should be able to make a simple test call to your Rotate function and tell us what you expected to get and what you got instead. But by then you can probably inspect every operation by hand and figure out what the problem is.

I'll tell you that your `angle' is in degrees and you never convert it to radians before sending it through sin() and cos(). Friends don't let friends use degrees. You can use degrees to get an angle from the user, to show it to the user or to set the value of a constant, but then you immediately convert it to radians and do everything internally as radians.

What Álvaro said.

You need to convert to radians.

You also need to translate to the origin, rotate and then translate back.

Here is your rotate method, this should probably work:


void Rotate(sf::Vector2f & p, double angle, sf::Vector2f r)
{
    double pi = 3.14159;
    float rad = angle*pi/180.0f;
    float s = sin(rad);
    float c = cos(rad);
    float rx = r.x;
    float ry = r.y;
	
    r.x -= p.x;
    r.y -= p.y;
	
    p.x = rx + r.x * c - r.y * s;
    p.y = ry + r.x * s + r.y * c;
}

As an aside, if you want to rotate multiple points by the same angle around the same center, you can re-use your sin() and cos() values. For example, rotating the four pointers of a rectangle around its center. Not sure how costly those functions are, so probably a moot point - just thought I'd mention it since I was needing to rotate the corners of a rectangle a few weeks back. laugh.png

I take this opportunity to plug complex numbers (as I have done in numerous other occasions):

#include <iostream>
#include <complex>

typedef std::complex<double> Point, Vector, Rotation;

Rotation rotation_from_angle(double angle) {
  return Rotation(std::cos(angle), std::sin(angle));
  
  // Or the alternative:
  //   return std::polar(1.0, angle);
}

Point rotate_around_center(Point point, Rotation rotation, Point center) {
  return center + rotation * (point - center);
}

double const pi = std::atan(1.0) * 4.0;
double const degrees = pi / 180.0;

int main() {
  Rotation quarter_turn_clockwise = rotation_from_angle(-90.0 * degrees);
  Point point(3,5);
  Point center(2,2);
  Point rotated = rotate_around_center(point, quarter_turn_clockwise, center);
  std::cout << rotated << '\n';
}

You posted entirely too much code. You should be able to make a simple test call to your Rotate function and tell us what you expected to get and what you got instead. But by then you can probably inspect every operation by hand and figure out what the problem is.

I'll tell you that your `angle' is in degrees and you never convert it to radians before sending it through sin() and cos(). Friends don't let friends use degrees. You can use degrees to get an angle from the user, to show it to the user or to set the value of a constant, but then you immediately convert it to radians and do everything internally as radians.

Ooh, i did not know that. Thank you!

What Álvaro said.

You need to convert to radians.

You also need to translate to the origin, rotate and then translate back.

Here is your rotate method, this should probably work:

void Rotate(sf::Vector2f & p, double angle, sf::Vector2f r)
{
double pi = 3.14159;
float rad = angle*pi/180.0f;
float s = sin(rad);
float c = cos(rad);
float rx = r.x;
float ry = r.y;

r.x -= p.x;
r.y -= p.y;

p.x = rx + r.x * c - r.y * s;
p.y = ry + r.x * s + r.y * c;
}

The example code, thank you kind sir!

I take this opportunity to plug complex numbers

Are you using complex numbers because they happen to be a pair of floats/doubles, or is there something about complex numbers that make them well-suited to this use? I'm rather ignorant of math. How is typedef'ing a std::complex better than typedef'ing some other kind of two-float class?

I take this opportunity to plug complex numbers

Are you using complex numbers because they happen to be a pair of floats/doubles, or is there something about complex numbers that make them well-suited to this use? I'm rather ignorant of math. How is typedef'ing a std::complex better than typedef'ing some other kind of two-float class?

If you look at rotate_around_center Alvaro utlized the properties of complex numbers to achieve the rotation. The only use of trig was in capturing the initial angle of rotation as a complex number. You may be interested the article A Visual, Intuitive Guide to Imaginary Numbers.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

This topic is closed to new replies.

Advertisement