#! /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()