Test Transformation Matrix - RIP (Rotate-In-Place)
Example Graphics Program

image missing

#! /usr/bin/python3 # ============================================================ # test Rotate-In-Place (RIP) # # Notes: # 1. RIP a shape defined by several lines # 2. as an exercise for the student, add code to draw a small # red circle at the pivot point # ============================================================ import coordinate_conversion as cc import transformation_matrix as tm import user_interface as ui import graphics as gr import numpy as np from time import sleep import copy WINHEIGHT = 801 # graphics window height WINWIDTH = 801 # graphics window width # ------------------------------------------------------------ # ---- the shape's points and lines # ------------------------------------------------------------ # ---- 4 points pts = [ (100,100),(150,250),(200,100),(150,50) ] # ---- pivot point PIVOT_POINT = (150,100) # ---- 4 lines LINES = [ (pts[0],pts[1]),(pts[1],pts[2]),(pts[2],pts[3]), (pts[3],pts[0]) ] # ------------------------------------------------------------ # ---- class - 2D transformation matrix # ---- # ---- notes: # ---- 1. Cartesian X,Y coordinates # ------------------------------------------------------------ class TransformationMatrix2D: # ---- initialize (create an identity matrix) def __init__(self): self.mtrx = np.identity(3) #---- reset matrix to initial condition def reset(self): self.mtrx = np.identity(3) # ---- transform a point's current coordinates (X,Y) # ---- using the transformation matrix def transform_coords(self,x,y): p = self.mtrx @ [x,y,1] return (p[0],p[1]) # ---- modify transformation matrix # ---- move a point to the origin (0,0) # ---- Note: X,Y are a point's current # ---- location (coordinates) def move_to_origin(self,x,y): m = tm.get_translation_matrix_2d(-x,-y) mm = m @ self.mtrx self.mtrx = mm # ---- modify transformation matrix # ---- move a point to (X,Y) # ---- Note: X,Y are a point's current # ---- location (coordinates) def move_to_location(self,x,y): m = tm.get_translation_matrix_2d(x,y) mm = m @ self.mtrx self.mtrx = mm # ---- modify transformation matrix # ---- rotate around the Z axis def rotate_around_z_axis(self,degrees): m = tm.get_z_rotation_matrix_2d(degrees) mm = m @ self.mtrx self.mtrx = mm # ---- return a deepcopy of the current # ---- transformation matrix def deepcopy_matrix(self): return copy.deepcopy(self.mtrx) # ---- return a shallow copy of the current # ---- transformation matrix def copy_matrix(self): return self.mtrx # ---- display the current transformation matrix def display_matrix(self): print(self.mtrx) # ------------------------------------------------------------ # ---- draw graphics window 2D axes # ---- # ---- Note: # ---- 1. the origin (0,0) is assumed to be at the center # ---- of the graphics window # ---- 2. no Z axis drawn # ---- 3. viewer is assumed to be at +Z infinity # ------------------------------------------------------------ def draw_graphics_window_axes(win, width=1, color='black'): wx = win.width # window width wy = win.height # window height wcx = round(wx/2.0) # window center X wcy = round(wy/2.0) # window center Y axis_objs = [] # ---- X axis xl = gr.Line(gr.Point(0,wcy),gr.Point(wx-1,wcy)) xl.setWidth(width) xl.setFill(color) xl.draw(win) axis_objs.append(xl) # ---- Y axis yl = gr.Line(gr.Point(wcx,0),gr.Point(wcx,wy-1)) yl.setWidth(width) yl.setFill(color) yl.draw(win) axis_objs.append(yl) return axis_objs # ------------------------------------------------------------ # ---- draw a line (X,Y Cartesian coordinates) # ---- viewer is at +Z infinity, no Perspective adjustment # ------------------------------------------------------------ def draw_a_line(win, mtrx, line, width=1, color='black', draw_obj=True): # ---- convert Cartesian coords (X,Y) to window coords p0 = line[0] wx0,wy0 = cc.center_to_win_coords(p0[0],p0[1], win.width,win.height) p1 = line[1] wx1,wy1 = cc.center_to_win_coords(p1[0],p1[1], win.width,win.height) # ---- create line graphics object obj = gr.Line(gr.Point(wx0,wy0),gr.Point(wx1,wy1)) obj.setOutline(color) obj.setWidth(width) obj.setFill(color) if draw_obj: obj.draw(win) return obj # ------------------------------------------------------------ # ---- remove graphics objects from graphics window # ------------------------------------------------------------ def clear_graphics_window(objs): for o in objs: o.undraw() objs = [] # ------------------------------------------------------------ # ---- test 1 - Rotate-In-Place (RIP) an object made of lines # ------------------------------------------------------------ def test_one(lines,pivot_point): # ---- make a deep copy of the input lines. this way they # ---- will not be modified by anything we do here # ---- (they can be re-used in further tests) lines_cpy = copy.deepcopy(lines) # ---- graphics object lists ax_objs = [] # axis graphics objects gr_objs = [] # other graphics objects # ---- create graphics window win = gr.GraphWin('Test RIP', WINWIDTH, WINHEIGHT) win.setBackground('white') # ---- draw X,Y coordinate axes ax_objs = draw_graphics_window_axes(win) # ---- create X,Y coordinate transformation matrix mtrx = TransformationMatrix2D() # ---- modify the transformation matrix to rotate # ---- points around the pivot point # ---- 1. move pivot point coords to origin # ---- 2. rotate (degrees) # ---- 3. move pivot point coords back mtrx.move_to_origin(PIVOT_POINT[0],PIVOT_POINT[1]) mtrx.rotate_around_z_axis(10) mtrx.move_to_location(PIVOT_POINT[0],PIVOT_POINT[1]) # ---- animate (draw/redraw) for _ in range(30): # ---- create a new set of lines transformed by # ---- the matrix lines_new = [] for line in lines_cpy: p0 = line[0] x0,y0 = mtrx.transform_coords(p0[0],p0[1]) p1 = line[1] x1,y1 = mtrx.transform_coords(p1[0],p1[1]) lines_new.append(((x0,y0),(x1,y1))) # ---- erase the old lines (graphics objects) clear_graphics_window(gr_objs) # ---- draw the new lines for line in lines_new: lobj = draw_a_line(win,mtrx,line) gr_objs.append(lobj) # ---- use the new lines in the next loop lines_cpy = lines_new sleep(0.5) # ---- wait for a mouse click in the window click = win.getMouse() win.close() print('END OF TEST ONE') # ------------------------------------------------------------ # ---- main # ------------------------------------------------------------ if __name__ == '__main__': test_one(LINES,PIVOT_POINT) print()