11

Is it possible to write a function in python that could rotate any 2d structure with the arguments being only the coordinates (x,y) of the points in the structure? Additional arguments would be included for axis, speed and direction.

To my understanding it would only be possible by calculating point distance from symmetrical points and the axis and therefore it would always vary and is thus impossible except for 2d structures made up of standard shapes (triangles, rectangles, squares etc)

Good examples would be appreciated.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • Really don't understand your second paragraph. But otherwise sure, if you have an point/axis to rotate about and an angle then you can just rotate each point independently. See http://stackoverflow.com/a/2259502/553404 for an example in c++ – YXD Nov 16 '13 at 20:24
  • Can you expand that second paragraph, please? Really not sure what you're implying there. – Shog9 Nov 18 '13 at 09:06

2 Answers2

23

First, we need a function to rotate a point around origin.

When we rotate a point (x,y) around origin by theta degrees, we get the coordinates:

(x*cos(theta)-y*sin(theta), x*sin(theta)+y*cos(theta))

If we want to rotate it around a point other than the origin, we just need to shift it so the center point becomes the origin. Now, we can write the following function:

from math import sin, cos, radians

def rotate_point(point, angle, center_point=(0, 0)):
    """Rotates a point around center_point(origin by default)
    Angle is in degrees.
    Rotation is counter-clockwise
    """
    angle_rad = radians(angle % 360)
    # Shift the point so that center_point becomes the origin
    new_point = (point[0] - center_point[0], point[1] - center_point[1])
    new_point = (new_point[0] * cos(angle_rad) - new_point[1] * sin(angle_rad),
                 new_point[0] * sin(angle_rad) + new_point[1] * cos(angle_rad))
    # Reverse the shifting we have done
    new_point = (new_point[0] + center_point[0], new_point[1] + center_point[1])
    return new_point

Some outputs:

print(rotate_point((1, 1), 90, (2, 1)))
# This prints (2.0, 0.0)
print(rotate_point((1, 1), -90, (2, 1)))
# This prints (2.0, 2.0)
print(rotate_point((2, 2), 45, (1, 1)))
# This prints (1.0, 2.4142) which is equal to (1,1+sqrt(2))

Now, we just need to rotate every corner of the polygon using our previous function:

def rotate_polygon(polygon, angle, center_point=(0, 0)):
    """Rotates the given polygon which consists of corners represented as (x,y)
    around center_point (origin by default)
    Rotation is counter-clockwise
    Angle is in degrees
    """
    rotated_polygon = []
    for corner in polygon:
        rotated_corner = rotate_point(corner, angle, center_point)
        rotated_polygon.append(rotated_corner)
    return rotated_polygon

Example output:

my_polygon = [(0, 0), (1, 0), (0, 1)]
print(rotate_polygon(my_polygon, 90))
# This gives [(0.0, 0.0), (0.0, 1.0), (-1.0, 0.0)]
Sweeney Todd
  • 880
  • 1
  • 11
  • 25
  • Love this answer, helps a ton! For some reason it doesn't work quite as well for angles greater than 360, so I added `while counterangle > 0: counterangle -= 360` and `while counterangle < 0: counterangle += 360` after that. This way, all angles are made positive and under 360. I also added `counterangle = 360 - angle` so that I can work with clockwise angles. – Luke Taylor May 07 '15 at 15:32
  • 1
    @Luke: You could probably just use `counterangle % 360` as the amount of rotation used in the function. – martineau Sep 23 '16 at 20:26
  • @martineau Yeah, now that I'm a year and a half farther into this stuff I realize that. Thanks ;) – Luke Taylor Sep 24 '16 at 14:40
  • Awesome answer - this is perfect for what I need! – zen_of_python Jun 05 '19 at 08:17
6

You can rotate 2-D arrays of points around an arbitrary point on the plane by first translating (moving) all the points so that the point of rotation becomes the origin (0, 0), applying the standard rotation formula to each of the point's x & y coordinates, and then "untranslating" them by the exact opposite amount of what was done initially.

In computer graphics this is often done by using something called transformation matrices.

The same concept can also easily be extended to work with 3-D points.

Edit:

See my answer to the question Rotate line around center point given two vertices for a fully worked out example using this technique.

martineau
  • 119,623
  • 25
  • 170
  • 301