0

I have four lines held in a Rectangle object. I'm trying to rotate the entire box by any angle, but I'm getting weird results.

Here's my current code:

void Line::rotate(int x_anchor, int y_anchor, double angle) {
    // Change the coordinate system
    int xOffset = m_pt1.x() - x_anchor;
    int yOffset = m_pt1.y() - y_anchor;

    // Move to 0, 0
    int xTemp = m_pt2.x() - xOffset;
    int yTemp = m_pt2.y() - yOffset;

    // Rotate
    double tCos = cos(angle);
    double tSin = sin(angle);
    double xNew = (xTemp * tCos) - (yTemp * tSin);
    double yNew = (xTemp * tSin) + (yTemp * tCos);

    // Make new
    m_pt2 = Point(xNew + xOffset, yNew + yOffset);
}

What I'm trying to do is move the origin, then move the line down to that orgin, rotate it, then put it back. By doing this, if I do something like:

void Rectangle::rotate(int x_anchor, int y_anchor, double angle) {
    m_t.rotate(x_anchor, y_anchor, angle);
    m_r.rotate(x_anchor, y_anchor, angle);
    m_b.rotate(x_anchor, y_anchor, angle);
    m_l.rotate(x_anchor, y_anchor, angle);
}

The box should rotate together. However, this doesn't even work for a line, so I'm not sure where I've gone wrong on my formula. This thread is what I'm referencing for the formula.

Thanks.


EDIT:

I've modified my code according to FalconUA's suggestion:

void Line::rotate(int x_anchor, int y_anchor, double angle) {
    /* Change the coordinate system */
    // Start point
    int xStartOffset = m_pt1.x() - x_anchor;
    int yStartOffset = m_pt1.y() - y_anchor;
    // End point
    int xEndOffset = m_pt2.x() - x_anchor;
    int yEndOffset = m_pt2.y() - y_anchor;

    /* Move to 0, 0 */
    // Start point
    int xStartTemp = m_pt2.x() - xStartOffset;
    int yStartTemp = m_pt2.y() - yStartOffset;
    // End point
    int xEndTemp = m_pt2.x() - xEndOffset;
    int yEndTemp = m_pt2.y() - yEndOffset;

    // Precalculate sin and cos
    double tCos = cos(angle);
    double tSin = sin(angle);

    /* Rotate */
    // Start point
    double xStartNew = (xStartTemp * tCos) - (yStartTemp * tSin);
    double yStartNew = (xStartTemp * tSin) + (yStartTemp * tCos);
    // End point
    double xEndNew = (xEndTemp * tCos) - (yEndTemp * tSin);
    double yEndNew = (xEndTemp * tSin) + (yEndTemp * tCos);

    // Make new points
    m_pt1 = Point(xStartNew + xStartOffset, yStartNew + yStartOffset);
    m_pt2 = Point(xEndNew + xEndOffset,     yEndNew + yEndOffset);
}

However, still not quite getting what I should.

Given:

Rectangle r(5, 5, 10, 10);

Which outputs:

xxxxxx
x    x
x    x
x    x
x    x
xxxxxx

And then if I rotate by 90 (PI / 2) degrees, which is done by this:

// Use the bottom left corner as the common point
rotate(m_l.getEnd().x(), m_l.getEnd().y(), PI / 2);

I get

x    x
 x    x
  x    x
   x    x
    x    x
     x
      x
       x
        x
    x    x
     x
      x
       x
        x
         x
Community
  • 1
  • 1
David
  • 4,744
  • 5
  • 33
  • 64
  • 1
    Why not use a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix)? – Axalo May 30 '15 at 12:07
  • @Axalo, that's what I'm trying to use. Look at the right side of `xNew` and `yNew`. – David May 30 '15 at 12:09
  • I mean why reinvent the wheel? See [here](http://scicomp.stackexchange.com/questions/351/recommendations-for-a-usable-fast-c-matrix-library). – Axalo May 30 '15 at 12:11
  • HW, gotta write my own. – David May 30 '15 at 12:12
  • One obvious fault is that `m_pt1` is never changed, so this can't work. Another oddity is that your rectangle has four lines, so overall eight points, all of which need to be rotated. There should be four pairs of equal points though, which could be optimized/refactored. That said, write a function that rotates a single point by an angle around a second point. If that function works, continue with further improvements, like avoiding repeated calculation of the rotation matrix. – Ulrich Eckhardt May 30 '15 at 12:40

1 Answers1

1

Seems like it happens because you're rotating lines relatively to the first point of the line. So, rotate not the line relatively to the first point, but rotate two points separately.

Update: if you have an anchor (xa, ya), and you want to rotate the point (x, y) around it. Your point can be represented as (xa + u, ya + v), where (u, v) = (x - xa, y - ya). So all you have to do is rotate teh vector (u, v) by using the formula with sin and cos that you've used above and the resulting point will be (xa + u_rotated, ya + v_rotated).

void Line::rotate(int x_anchor, int y_anchor, double angle) {
    // the vector to rotate 
    int rotvec_x1 = m_pt1.x() - x_anchor;
    int rotvec_y1 = m_pt1.y() - y_anchor;

    // the vector to rotate
    int rotvec_x2 = m_pt2.x() - x_anchor;
    int rotvec_y2 = m_pt2.y() - y_anchor;

    // pre-calculation for sin and cos
    double tCos = cos(angle);
    double tSin = sin(angle);

    // rotating first vector
    double rotvec_x1_new = (rotvec_x1 * tCos) - (rotvec_y1 * tSin);
    double rotvec_y1_new = (rotvec_x1 * tSin) + (rotvec_y1 * tCos);

    // rotating second vector
    double rotvec_x2_new = (rotvec_x2 * tCos) - (rotvec_y2 * tSin);
    double rotvec_y2_new = (rotvec_x2 * tSin) + (rotvec_y2 * tCos);

    // Make new
    m_pt1 = Point(x_anchor + rotvec_x1_new, y_anchor + rotvec_y1_new);
    m_pt2 = Point(x_anchor + rotvec_x2_new, y_anchor + rotvec_y2_new);
}
Chan Kha Vu
  • 9,834
  • 6
  • 32
  • 64
  • Better, but still not working. See my edit. I put my modified code, and what I'm seeing for output. – David May 30 '15 at 12:46
  • @David Sorry, my previous code was incorrect and unclear because I messed the variable names. I've edited the code and added explanation of the idea of point rotation. I've also tested it on some input and seems like it is correct. – Chan Kha Vu May 30 '15 at 13:31
  • Ah, okay. That's working for right angles, but not non-right angles. Any idea on that? – David May 30 '15 at 13:52
  • I think it has something to do with the formula only working in the 1st and 3rd quadrant. So now on to solve that. Appreciate all your help! – David May 30 '15 at 20:53