Rotate a rectangle consisting of 4 tuples to left or right
<p>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:
 <code>x, y=40000,40000</code>
I've also got a length x, and a length y, <code>x_displacement</code>, and <code>y_displacement</code>. I've got an angle, <code>theta</code>, 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: 
<a href="http://i.imgur.com/pp3hFyA.jpg" rel="nofollow">http://i.imgur.com/pp3hFyA.jpg</a></p>

<pre><code>    x_displacement=100
    y_displacement=100
    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
</code></pre>

<p>Coord is a class that holds an x and a y value. <code>coords</code> is a list of Coord class items.</p>

<pre><code>    c = Coord(x, y)
    coords.append(c)
    c = Coord(x1, y1)
    coords.append(c)
    c = Coord(x2, y2)
    coords.append(c)
    c = Coord(x3, y3)
    coords.append(c)
    #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))))
    coords=newcoords
</code></pre>

<p>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!</p>

<p>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:</p>

<ul>
<li>First construct the shape at the (0, 0) point</li>
<li>Rotate it</li>
<li>Translate it out to where it needs to be</li>
</ul>

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

<pre><code>import math


def rotate(xy, theta):
    # https://en.wikipedia.org/wiki/Rotation_matrix#In_two_dimensions
    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]
</code></pre>

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

python python-3.x rotation gis