#!/usr/bin/python3
# ===================================================================
# draw a wire frame object's surfaces (in this case a cube)
#
# 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 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)
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
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')
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
# -------------------------------------------------------------------
# ---- 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)
# ---- create transformation matrix
m0 = tm.get_identity_matrix_3d()
m1 = tm.get_x_rotation_matrix_3d(10)
m2 = tm.get_y_rotation_matrix_3d(20)
m3 = tm.get_z_rotation_matrix_3d(30)
mtrx = m3 @ m2 @ m1
# ---- draw (cube) surfaces
draw_surfaces(win,sur,nvpts,mtrx)
# ---- pause program
ui.pause()