MeesterTeem MeesterTeem - 1 year ago 71
Python Question

Rotate a rectangle consisting of 4 tuples to left or right

I'm working on a program to manipulate GIS data, but for this precise problem, I'm trying to rotate a rectangle of 4 points around the bottom left corner. I've got 1 tuple describing the bottom left corner:

x, y=40000,40000

I've also got a length x, and a length y,
, and
. I've got an angle,
, in degrees. I want to rotate the rectangle by up to 90 degrees left or right, so theta can be -89 to 89 degrees. Negative angles should rotate the corners to the left; positive angles to the right.I've represented the rectangle as such:

x = 40000
y = 40000
x1 = x
y1 = y + a.y_displacement
x2 = x + a.x_displacement
y2 = y + a.y_displacement
x3 = x + a.x_displacement
y3 = y
#describes the other 4 corners of the rectangle

Coord is a class that holds an x and a y value.
is a list of Coord class items.

c = Coord(x, y)
c = Coord(x1, y1)
c = Coord(x2, y2)
c = Coord(x3, y3)
#Adds each corner to the list of coordinates
theta = math.radians(a.angle)
newcoords = []
for c in coords:
newcoords.append(Coord((c.x * math.cos(theta) - c.y * math.sin(theta)),
(c.x * math.sin(theta) + c.y * math.cos(theta))))

I suspect that there's something relatively trivial that I'm doing wrong, but I've been stuck on this problem for quite some time.
This code produces a new rectangle that is either misshapen, or has negative corners, rather than slightly left-rotated corners as wanted.
I've seen many posts on here about rotating rectangles, but none seem to be a direct duplicate, because they do not handle negative angles. I'd appreciate any pointers!

Answer Source

As a few commenters mentioned, you are rotating around the (0, 0) point, rather than the lower left point. As we are constructing the coordinates we can:

  • First construct the shape at the (0, 0) point
  • Rotate it
  • Translate it out to where it needs to be

The below gives an example using plain lists rather than your Coord object, but I'm sure it makes the point.

import math

def rotate(xy, theta):
    cos_theta, sin_theta = math.cos(theta), math.sin(theta)

    return (
        xy[0] * cos_theta - xy[1] * sin_theta,
        xy[0] * sin_theta + xy[1] * cos_theta

def translate(xy, offset):
    return xy[0] + offset[0], xy[1] + offset[1]

if __name__ == '__main__':
    # Create the square relative to (0, 0)
    w, h = 100, 100

    points = [
        (0, 0),
        (0, h),
        (w, h),
        (w, 0)

    offset = (40000, 50000)
    degrees = 90
    theta = math.radians(degrees)

    # Apply rotation, then translation to each point
    print [translate(rotate(xy, theta), offset) for xy in points]

As a bonus, this should work with any set of points defined relative to (0, 0), regardless of whether they form any sensible polygon.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download