#!/usr/bin/python3 # =================================================================== # draw a wire frame object's surfaces animation # # each surface has a different color. use a normal vector to # determine if a surface should be drawn or not. # =================================================================== import coordinate_conversion as cc import transformation_matrix as tm import user_interface as ui import normal_vector as nv import draw_xy_axes as ax import graphics as gr import numpy as np import time, re, os, platform, sys win_height = 801 # window height win_width = 801 # window width # ---- each surface has a different color surcolor= [ 'red','green','blue','cyan','yellow','white' ] # ---- wire frame cube (points, lines, surfaces, normal vectors) # # 5+----------+6 # /| /| # / | / | # 1+----------+2 | # | | | | # | 4+-------|--+7 # | / | / # |/ |/ # 0+----------+3 # # # ---- wire frame (cube) corner points pts = [ (-50,-50,50), (-50,50,50), # point 0,1 (50,50,50), (50,-50,50), # point 2,3 (-50,-50,-50), (-50,50,-50), # point 4,5 (50,50,-50), (50,-50,-50) ] # point 5,7 # # ---- pivot point pivot = (0, 0, 0) # # ---- wire frame (cube) lines lns = [ (pts[0],pts[1]), (pts[1],pts[2]), # line 0,1 (pts[2],pts[3]), (pts[3],pts[0]), # line 2,3 (pts[4],pts[5]), (pts[5],pts[6]), # line 4,5 (pts[6],pts[7]), (pts[7],pts[4]), # line 6,7 (pts[0],pts[4]), (pts[1],pts[5]), # line 8,9 (pts[2],pts[6]), (pts[3],pts[7]) ] # line 10,11 # # ---- wire frame (cube) surfaces sur = [ (pts[0],pts[1],pts[2],pts[3]), # surface 0 red (pts[7],pts[6],pts[5],pts[4]), # surface 1 green (pts[4],pts[5],pts[1],pts[0]), # surface 2 blue (pts[3],pts[2],pts[6],pts[7]), # surface 3 cyan (pts[1],pts[5],pts[6],pts[2]), # surface 4 yellow (pts[0],pts[3],pts[7],pts[4]) ] # surface 5 white # # ---- wire frame (cube) normal vector points for each surface # ---- (points used to calculate normal vector) nvpts = [ (pts[0],pts[1],pts[2]), # nv surface 0 (pts[7],pts[6],pts[5]), # nv surface 1 (pts[4],pts[5],pts[1]), # nv surface 2 (pts[3],pts[2],pts[6]), # nv surface 3 (pts[1],pts[5],pts[6]), # nv surface 4 (pts[0],pts[3],pts[7]) ] # nv surface 5 # ------------------------------------------------------------------- # ---- test normal vector # ---- return True if it leaning towards the viewer (+z) # ---- return False if is leaning away from the viewer (-z) # ------------------------------------------------------------------- def test_normal_vector(pts,mtrx): # ---- convert normal vector original points to arrays orgpt0 = np.array([pts[0][0],pts[0][1],pts[0][2],1]) orgpt1 = np.array([pts[1][0],pts[1][1],pts[1][2],1]) orgpt2 = np.array([pts[2][0],pts[2][1],pts[2][2],1]) # ---- transform original points using transformation matrix newpt0 = mtrx @ orgpt0 newpt1 = mtrx @ orgpt1 newpt2 = mtrx @ orgpt2 # ---- create normal vector from new points v = nv.create_normal_vector(newpt0,newpt1,newpt2,1000) ##print(f'nv = {v}') if v[2] > 0: # z greater than zero? return True return False # ------------------------------------------------------------------- # ---- draw surface # ------------------------------------------------------------------- def draw_surface(win,pts,mtrx,color='red'): points = [] # list of points defining # surface (polygon) # ---- create a list of graphics point # ---- (required by graphics polygon function) for p in pts: # ---- original coordinates (as an array) orgcord = np.array( [ p[0],p[1],p[2],1] ) # ---- transform coordinates using transformation matrix newcord = mtrx @ orgcord # ---- convert new coordinates to window coordinates # ---- so the can be drawn x,y = cc.center_to_win_coords(newcord[0],newcord[1], win.width,win.height) # ---- add window coordinates to the list of graphics points points.append(gr.Point(x,y)) # ---- draw the polygon using the list of graphics points pobj = gr.Polygon(points) pobj.setFill(color) pobj.draw(win) # ---- return the graphics object in case we need it later return pobj # ------------------------------------------------------------------- # ---- draw surfaces # ---- # ---- win the window to draw in # ---- sur a list of the surfaces to be drawn # ---- nvpts points used to calc normal vector # ---- mtrx transformation matrix # ------------------------------------------------------------------- def draw_surfaces(win,sur,nvpts,mtrx): i = 0 # surface color index l = len(surcolor) # length of color list j = 0 # normal vector list index pobjs = [] for s in sur: # for each surface if i >= l: # end of color list i = 0 # start over at 0 if test_normal_vector(nvpts[j],mtrx): ##print(f'surface {j} {surcolor[i]:6} draw') pobjs.append(draw_surface(win,s,mtrx,surcolor[i])) ##else: ##print(f'surface {j} {surcolor[i]:6} don\'t draw') i += 1 # next color j += 1 # next normal vector return pobjs # ------------------------------------------------------------------- # ---- main # ------------------------------------------------------------------- # ---- running Python3? if not ui.running_python3: print() print('Must run Python3 - exit program') print() sys.exit() # ---- create drawing window win = gr.GraphWin("Solid Object", win_width, win_height) win.setBackground("white") # ---- draw X,Y coordinate axes ax.draw_xy_axes(win,True) # ---- loop degx = 10 degy = 20 degz = 30 for _ in range(20): # ---- create transformation matrix m0 = tm.get_identity_matrix_3d() m1 = tm.get_x_rotation_matrix_3d(degx) m2 = tm.get_y_rotation_matrix_3d(degy) m3 = tm.get_z_rotation_matrix_3d(degz) m4 = tm.get_translation_matrix_3d(100,100,0) mtrx = m4 @ m3 @ m2 @ m1 # ---- draw (cube) surfaces pobjs = draw_surfaces(win,sur,nvpts,mtrx) time.sleep(0.3) for p in pobjs: p.undraw() degx += 20 degy += 20 degz += 20 # ---- pause program ui.pause()