0

I am using Zelle graphics, but I suppose it is the same for any graphics program. From what I can tell, Zelle graphics does not have a "setheading" or "rotate" command for the rectangle (this is probably because the bounding box is created with two points). In turtle graphics it is easy with setheading(). So presently, I have a class that creates a polygon. I have a draw method and a rotate method. In the rotate method I am changing the Point(x1,y1) for each corner in a FOR LOOP. I broke out some graph paper to get the initial first few points to rotate, there is complex math I believe that would make this more palatable. Presently this is my init method with these attributes, but I am sure there is a better way:

    class create():
def __init__(self, p1x,p1y,p2x,p2y,p3x,p3y,p4x,p4y):
    self.p1x = p1x
    self.p2x = p2x
    self.p3x = p3x
    self.p4x = p4x
    self.p1y = p1y
    self.p2y = p2y
    self.p3y = p3y
    self.p4y = p4y

NOTE : this is not the entirety of my code. This is just the INIT method. I don't want anyone to think I have not tried this. I have with working code to rotate a polygon to the left about 5 points, but this is just using self.p1x=self.p1x+1 - I know this is not the correct way to rotate a rectangle. But at present I have a working model for rotating it slightly.

EDIT : Here is the new work I have tried. I am still trying to understand this :

  • I need the midpoint, because the equation is derived from it. That is after I get the rotation correct. I am going to assume a midpoint in a 10x10 starting from the origin is going to be 5,5 for this example.

Does this code look ok so far? I am going to assume a rotation angle of 10 degrees for this example.

import math
#assume a 10 x 10 rectangle top left corner 0,0
#top left coords
x=0
y=0
#midpoints
midx = 5
midy = 5

#degrees to radians???????
angle=math.radians(10)

#new top left x
newx1 = x - midx * math.cos(angle) - (y-midy)*math.sin(angle)+ midx
#new top left y
newy1 = y - midy * math.sin(angle) + (x-midx)*math.cos(angle)+ midy
print(newx1, newy1)
  

The output is : 0.9442021232736115 -0.7922796533956911

netrate
  • 423
  • 2
  • 8
  • 14
  • Does rotate mean “at 90 degrees”, or can it be any angle? If at any angle, is it correct that rotation happens around the midpoint? – user2864740 Dec 24 '21 at 21:44
  • Yes rotate at any angle. So any angle the rectangle/polygon is facing - I need it to rotate correctly. Yes I do realize at the midpoint, things change and the numbers for the initial rotation go in reverse? – netrate Dec 24 '21 at 23:11
  • Basic idea is to then rotate each point (individually) about the midpoint (after adjusting the point relative to midpoint (such that it becomes relative to origin) before and after) — https://stackoverflow.com/q/2259476/2864740 (several useful answers) – user2864740 Dec 25 '21 at 01:58
  • It might be easier (and avoid math errors over time as rotating to infinity..) to keep the original points and center (midpoint here) and current rotation angle and position of the center “in the world”. Then adjust the rotation angle and then compute points (for display/collision) from the original points and current angle (leaving the original points alone). If the original center is defined as the origin (eg. -1,1 is top left and 1,-1 is bottom right), then there is no need to first adjust the original points to the origin as this is implied. – user2864740 Dec 25 '21 at 02:05
  • I'm not sure how to approach this midpoint challenge you stated in your comment. I'm not using angles and I think that is one of the issues, how do I computer the angles so I can adjust the points? – netrate Dec 25 '21 at 16:06
  • For a minute ignore the midpoint. Assume the square has a top left of -1,1 and a bottom right of 1,-1. Now, write code to rotate one of these points (X,Y) about the origin by an arbitrary angle R (0 to 360) degrees. That’s it — see the linked question. – user2864740 Dec 25 '21 at 20:44
  • Then it’s only a final matter of applying the transform to all the points and shifting the original point relative to the origin (following the process to rotate a single point (X,Y) around the origin by R) and finally shifting the computed points back. – user2864740 Dec 25 '21 at 20:46
  • https://academo.org/demos/rotation-about-point/ , https://www.khanacademy.org/_render , https://danceswithcode.net/engineeringnotes/rotations_in_2d/rotations_in_2d.html (extends with offset (to different center of rotation)). Math.cos/sin Python use radians, so remember to convert from degrees first. – user2864740 Dec 25 '21 at 20:50
  • Added new content to the original question - I am trying this with 45 and 90 degrees and the answers are coming out wrong, so I have messed up somewhere. – netrate Dec 29 '21 at 21:16
  • you forgot brackets in `(x-midx)*cos` and `(y-midy)*sin` - so you calculate `x-(midx*cos)` and `y-(midy*sin)`. For `x=0`, `y=0`it gives the same result but for other values it gives wrong result. Maybe you could draw both objects to see how much they are different. – furas Feb 24 '22 at 17:53

1 Answers1

0

This is version which works for me - it rotates Point around midx, midy with angle.

First it has to move middle to (0,0) and get current angle.

def rotate_point(point, angle, midx, midy):
    
    old_x = point.x
    old_y = point.y
    
    old_cx = old_x - midx  # move middle to (0,0)
    old_cy = old_y - midy  # move middle to (0,0)
    
    angle_radians = math.radians(angle)

    angle_sin = math.sin(angle_radians)
    angle_cos = math.cos(angle_radians)
         
    new_cx = old_cx * angle_cos - old_cy * angle_sin
    new_cy = old_cx * angle_sin + old_cy * angle_cos
    
    new_x =  new_cx + midx  # move back
    new_y =  new_cy + midy  # move back
    
    point = Point(new_x, new_y)
    
    return point

And next I can use it to rotate Polygon

def rotate_polygon(polygon, angle, midx, midy):
    
    new_points = []
    
    for p in polygon.getPoints():
        new_p = rotate_point(p, angle, midx, midy)
        new_points.append(new_p)
        
    return Polygon(*new_points)

Here full code which rotates

  • rectangle around middle point (angles: 30, 60),
  • triangle around one of corners (angles: 90, 180, 270).

enter image description here

import math
from graphics import *

def rotate_point(point, angle, midx, midy):
    
    old_x = point.x
    old_y = point.y
    
    old_cx = old_x - midx  # move middle to (0,0)
    old_cy = old_y - midy  # move middle to (0,0)
    
    angle_radians = math.radians(angle)

    angle_sin = math.sin(angle_radians)
    angle_cos = math.cos(angle_radians)
         
    new_cx = old_cx * angle_cos - old_cy * angle_sin
    new_cy = old_cx * angle_sin + old_cy * angle_cos
    
    new_x =  new_cx + midx  # move back
    new_y =  new_cy + midy  # move back
    
    point = Point(new_x, new_y)
    
    return point

def rotate_polygon(polygon, angle, midx, midy):
    
    new_points = []
    
    for p in polygon.getPoints():
        new_p = rotate_point(p, angle, midx, midy)
        new_points.append(new_p)
        
    return Polygon(*new_points)
    
# --- main ---


win = GraphWin()

# --- rectangle ---

x = 100
y = 100
w = 50
h = 50
midx = x + w//2  # rectangle middle
midy = y + h//2  # rectangle middle 

p1 = Polygon(Point(x, y), Point(x+w, y), Point(x+w, y+h), Point(x, y+h), Point(x, y))
p1.draw(win)

p2 = rotate_polygon(p1, 30, midx, midy)
p2.draw(win)

p3 = rotate_polygon(p1, 60, midx, midy)
p3.draw(win)

# --- triangle ---

x = 60
y = 60
w = 50
h = 50
midx = x #+5  # triangle corner
midy = y #+5  # triangle corner

t1 = Polygon(Point(x, y), Point(x+w, y), Point(x+w//2, y+h), Point(x, y))
t1.draw(win)

t2 = rotate_polygon(t1, 90, midx, midy)
t2.draw(win)

t3 = rotate_polygon(t1, 180, midx, midy)
t3.draw(win)

t4 = rotate_polygon(t1, 270, midx, midy)
t4.draw(win)

# ---

win.getMouse()
win.close()
furas
  • 134,197
  • 12
  • 106
  • 148