Rotate polygon around center point by changing x and y values.

edited July 2014 in Share Your Work

I searched to find an approach and wrestled with this code. High School geometry long forgotten. My goal was to use the mouse wheel to rotate the polygon. Below is the code that includes both sin() and cos() as I was working through the details. My hope is that others will find this useful.

(* Edited to include CenterDiagram())

RotatePolygonSketch

/*
 r = sqrt(x**2+y**2)
 cos(Θ) = x/r
 sin(Θ) = y/r
 x= cos(Θ)*r
 y= sin(Θ)*r
 .                            |
 .                            |
 .            MINUSPLUS       |          PLUSPLUS
 .  180 - degrees(asin(y/r))  |     degrees(asin(y/r))
 .        degrees(acos(x/r))  |     degrees(acos(x/r))
 .                            |
 .                            |
 -----------------------------+------------------------
 .                            |
 .                            |
 .            MINUSMINUS      |          PLUSMINUS
 .  180 - degrees(asin(y/r))  |     360 + degrees(asin(y/r))
 .  360 - degrees(acos(x/r))  |     360 - degrees(acos(x/r))

 */
static final float ROTATION_INCREMENT = 5f;
static final int XYQUAD_PLUSPLUS = 1;
static final int XYQUAD_MINUSPLUS = 2;
static final int XYQUAD_MINUSMINUS = 3;
static final int XYQUAD_PLUSMINUS = 4;


void wheelRotate(int incr)
{
  int xOffset = -width/2;
  int yOffset = -height/2;
  noLoop();
  centerDiagram();
  //transform
  for (int i = 0; i< verts.size (); i++)
  {
    Point p = verts.get(i);
    p.x += xOffset;
    p.y += yOffset;
  }

  // rotate
  for (int i = 0; i< verts.size (); i++)
  {
    float x;
    float y;
    float r;
    float sTheta = 0;
    float cTheta = 0;
    float theta;
    float radians;
    int mode;
    Point p = verts.get(i);
    x = p.x;
    y = p.y;
    mode = quadrant(x, y);
    r = sqrt(pow(x, 2)+pow(y, 2)); 
    switch(mode)
    {
    case XYQUAD_PLUSPLUS:
      println("XYQUAD_PLUSPLUS");
      sTheta = degrees(asin(y/r));
      cTheta = degrees(acos(x/r));
      break;
    case XYQUAD_MINUSPLUS:
      println("XYQUAD_MINUSPLUS");
      sTheta = 180 - degrees(asin(y/r));
      cTheta = degrees(acos(x/r));
      break;
    case XYQUAD_MINUSMINUS:
      println("XYQUAD_MINUSMINUS");
      sTheta = 180 - degrees(asin(y/r));
      cTheta = 360 - degrees(acos(x/r));
      break;
    case XYQUAD_PLUSMINUS:
      println("XYQUAD_PLUSMINUS");
      sTheta = 360 + degrees(asin(y/r));
      cTheta = 360 - degrees(acos(x/r));
      break;
    }
    theta = sTheta + (incr * ROTATION_INCREMENT);
    if (theta > 360) 
    {
      theta -= 360;
    } else if (theta < 0)
    {
      theta += 360;
    }
    radians = radians(theta);
    println("cTheta="+cTheta+" sTheta="+sTheta);
    print(i+" theta="+theta+" x="+x+" y="+y+" r="+r);
    println(" sin("+y+"/"+r+")="+sin(y/r)+" asin="+degrees(asin(y/r)));     
    p.x = (int)round((cos(radians)*r));
    p.y = (int)round((sin(radians)*r));
  }

  // re-transform
  for (int i = 0; i< verts.size (); i++)
  {
    Point p = verts.get(i);
    p.x -= xOffset;
    p.y -= yOffset;
  }
  centerDiagram();
  loop();
}

int quadrant(float x, float y)
{
  if (x>0)
  {
    if (y>0)
    {
      return XYQUAD_PLUSPLUS;
    } else
    {
      return XYQUAD_PLUSMINUS;
    }
  } else if (y > 0)
  {
    return XYQUAD_MINUSPLUS;
  } else
  {
    return XYQUAD_MINUSMINUS;
  }
} 

void centerDiagram()
{
  int minX = width;
  int maxX = 0;
  int minY = height;
  int maxY = 0;
  int xOffset = 0;
  int yOffset = 0;

  for (int i = 0; i<verts.size (); i++)
  {
    Point p = verts.get(i);
    xOffset += width/2 - p.x;
    yOffset += height/2 - p.y;
  }
  xOffset /= verts.size();
  yOffset /= verts.size();
  for (int i = 0; i<verts.size (); i++)
  {
    Point p = verts.get(i);
    p.x = p.x + xOffset;
    p.y = p.y + yOffset;
  }
}

Comments

  • edited July 2014

    "My hope is that others will find this useful."
    Then, that's not a question? The How To category is to ask questions how to make something, not to give solutions. The name of the category can be ambiguous, but the category descriptions should make it clear.

    So I moved the topic to Share your Work. And changed the topic type to Discussion instead of Question. Thanks for sharing.

  • isn't this just the standard 2d rotation matrix but more complicated? there's no need to convert the input points to polar co-ords and back again, just multiply each point by the relevant matrix where theta is the increment.

    http://en.wikipedia.org/wiki/Rotation_matrix

  • Bug: Cannot find anything named "CENTER_BY_AVE_XY"! [..]

  • GoToLoop, I edited the post and included centerDiagram().

    koogs, maybe a standard rotation matrix would do the trick. My early attempts at using

    x' = x*cos Θ - y*sin Θ;
    y' = x*sin Θ + y*cos Θ;
    

    failed. However that could have been a radians vs. degrees issue. I worked through the details of sin(), asin() and radians() and degrees() and then derived the solution above.

  • GoToLoop, I edited the post and included centerDiagram().

    koogs, maybe a standard rotation matrix would do the trick. My early attempts at using x' = x \cos \theta - y \sin \theta\,, y' = x \sin \theta + y \cos \theta\,.

    failed. However that could have been a radians vs. degrees issue. I worked through the details and derived a solution

  • edited July 2014

    The code has been improved, and uses floats instead of ints, resulting is much more accurate rotation.

    The improved code is in Why does Draw() flicker when using noLoop() ... loop() in the "Here is the well behaved code:" comment. It also includes zoom.

Sign In or Register to comment.