from tkinter import *
import math
unitScale = 100
class Cube():
def __init__(self, canvas):
self.canvas = canvas
self.canvasWidth=800
self.canvasHeight = 500
self.cubePos = {'x':0, 'y':0, 'z':0}
self.cubeSize = 0.5
self.cubeRadius = None
self.zrot = 0
self.sin = None
self.cos = None
self.vertices = {'a':[0, 0], #cube coordinates in 3D space: [x, y]
'b':[0, 0],
'c':[0, 0],
'd':[0, 0],
'z':[0, 0]} #[z0, z1] for all vertices
self.uPos = -3
self.vanishingPoints = [0, 0] #[x1, x2]
self.pVertices = {'a0':[0, 0], #picturePlance vertices: [x, y]
'b0':[0, 0],
'c0':[0, 0],
'd0':[0, 0],
'a1':[0, 0],
'b1':[0, 0],
'c1':[0, 0],
'd1':[0, 0]}
#keybinds
self.canvas.bind("<ButtonPress-1>", self.KeyButtonPress)
self.canvas.bind("<ButtonRelease-1>", self.KeyButtonRelease)
self.canvas.bind("<B1-Motion>", self.KeyOnMotion)
self.canvas.bind("<Shift-B1-Motion>", self.KeyShiftOnMotion)
self.canvas.bind("<Control-B1-Motion>", self.KeyControlOnMotion)
self.canvas.bind("<Alt-B1-Motion>", self.KeyAltOnMotion)
self.canvas.bind('<Configure>', self.resize)
self._drag_data = [0, 0] #[x, y]
self.refresh()
def KeyButtonPress(self, event):
'''Begin drag of the cube'''
self._drag_data = [event.x, event.y]
def KeyButtonRelease(self, event):
self._drag_data = [0, 0]
def KeyOnMotion(self, event):
global unitScale
delta_x = event.x - self._drag_data[0]
delta_y = event.y - self._drag_data[1]
self.cubePos['x'] += delta_x/unitScale
self.cubePos['z'] += delta_y/unitScale
self.refresh()
self._drag_data = [event.x, event.y]
def KeyShiftOnMotion(self, event):
delta_x = event.x - self._drag_data[0]
self.zrot += delta_x * 0.2
self.refresh()
self._drag_data = [event.x, event.y]
def KeyControlOnMotion(self, event):
delta_y = event.y - self._drag_data[1]
self.uPos += delta_y * -0.01*self.uPos
self.refresh()
self._drag_data = [event.x, event.y]
def KeyAltOnMotion(self, event):
delta_x = event.x - self._drag_data[0]
delta_y = event.y - self._drag_data[1]
delta = delta_x + delta_y
self.cubeSize += delta * 0.01*self.cubeSize
self.refresh()
self._drag_data = [event.x, event.y]
def draw(self):
def drawCube(self):
keys = ['a', 'b', 'c', 'd']
for i in range(0,4):
coords = self.pVertices[keys[i]+'0']
coords += self.pVertices[keys[i-1]+'0']
coords += self.pVertices[keys[i-1]+'1']
coords += self.pVertices[keys[i]+'1']
self.canvas.create_polygon(coords,tags = 'cube', width=1,
fill='', outline='#000000')
def drawVanishingPoints(self):
global unitScale
vp1 = [self.vanishingPoints[0]*unitScale, 0]
vp2 = [self.vanishingPoints[1]*unitScale, 0]
b0 = self.pVertices['b0']
b1 = self.pVertices['b1']
c0 = self.pVertices['c0']
c1 = self.pVertices['c1']
d0 = self.pVertices['d0']
d1 = self.pVertices['d1']
vpColor = '#aaaaaa'
line1 = vp1+d0+d1
line2 = vp2+b0+b1
line3 = vp1+c0+vp2+c1
self.canvas.create_polygon(line1, tags='vp', dash=(2, 1),
fill='', outline=vpColor)
self.canvas.create_polygon(line2, tags='vp', dash=(2, 1),
fill='', outline=vpColor)
self.canvas.create_polygon(line3, tags='vp', dash=(2, 1),
fill='', outline=vpColor)
self.canvas.delete('cube')
self.canvas.delete('vp')
drawVanishingPoints(self)
drawCube(self)
self.canvas.delete('lpup')
self.canvas.delete('rpup')
ex = self.cubePos['x']*3
eu = (-10-self.uPos)
w.create_arc(-150+ex-eu,-55,-100+ex-eu,-105,extent=180,tags='lpup',fill='#000000')
w.create_arc( 100+ex+eu,-55, 150+ex+eu,-105,extent=180,tags='rpup',fill='#000000')
def picturePlaneVerticesCoords(self):
global unitScale
uPos = self.uPos
for key1 in ['a', 'b', 'c', 'd']:
x = self.vertices[key1][0]
y = self.vertices[key1][1]
for n in ['0', '1']:
z = self.vertices['z'][int(n)]
key2 = key1+n
ppx = (x-x/(y-uPos)*y)*unitScale
ppy = (z-z/(y-uPos)*y)*unitScale
self.pVertices[key2] = [ppx, ppy]
def printCoords(self):
print('Cube coordinates:')
for key, value in sorted(self.vertices.items()):
print(key, value)
print('Screen coordinates:')
for key, value in sorted(self.pVertices.items()):
print(key, value)
def refresh(self):
self.cubePosChange()
self.cubeSizeChange()
self.uPosChange()
self.zrotChange()
self.verticesCoords()
self.vanishingPointCoords()
self.picturePlaneVerticesCoords()
self.draw()
def resize(self, event):
w,h = event.width, event.height
self.canvasWidth = w
self.canvasHeight = h
self.canvas.config(scrollregion=(-w/2,-h/2,w/2,h/2))
def vanishingPointCoords(self):
'''Sets coordinates for vanishing points'''
vp1Rot = self.zrot-45
vp1Tan = math.tan(math.radians(vp1Rot))
vp2Rot = self.zrot+45
vp2Tan = math.tan(math.radians(vp2Rot))
vp1 = 0-self.uPos*vp1Tan
vp2 = 0-self.uPos*vp2Tan
self.vanishingPoints = [vp1, vp2]
def verticesCoords(self):
'''Sets coordinates for cube vertices'''
x = self.cubePos['x']
y = self.cubePos['y']
z = self.cubePos['z']
s = self.cubeSize
r = self.cubeRadius
sin = self.sin
cos = self.cos
self.vertices['a'][0] = x-r*sin
self.vertices['b'][0] = x+r*cos
self.vertices['c'][0] = x+r*sin
self.vertices['d'][0] = x-r*cos
a = y-r*cos
b = y-r*sin
c = y+r*cos
d = y+r*sin
yOffset = min([a, b, c, d])
self.vertices['a'][1] = a-yOffset
self.vertices['b'][1] = b-yOffset
self.vertices['c'][1] = c-yOffset
self.vertices['d'][1] = d-yOffset
self.vertices['z'] = [z+s, z-s]
def cubePosChange(self):
global unitScale
xlim = self.canvasWidth/(2*unitScale)
zlim = self.canvasHeight/(2*unitScale)
if self.cubePos['x'] < -xlim:
self.cubePos['x'] = -xlim
elif self.cubePos['x'] > xlim:
self.cubePos['x'] = xlim
if self.cubePos['z'] < -zlim:
self.cubePos['z'] = -zlim
elif self.cubePos['z'] > zlim:
self.cubePos['z'] = zlim
def cubeSizeChange(self):
self.cubeRadius = (2*self.cubeSize**2)**0.5
def uPosChange(self):
uPosLim = (-0.05, -10)
if self.uPos < uPosLim[1]:
self.uPos = uPosLim[1]
elif self.uPos > uPosLim[0]:
self.uPos = uPosLim[0]
def zrotChange(self):
rotlim = 45 #rotation limit
if self.zrot > rotlim:
self.zrot -= rotlim*2
elif self.zrot < -rotlim:
self.zrot += rotlim*2
self.sin = math.sin(math.radians(self.zrot))
self.cos = math.cos(math.radians(self.zrot))
master = Tk()
w = Canvas(master, width=800, height = 500, bg='#ffffff')
w.pack(expand=TRUE, fill=BOTH)
w.config(scrollregion=(-400,-250,400,250))
w.create_line(-1000, 0, 1000, 0, fill='#40cff0') #horizon
w.create_arc(-220,-200,220,200,extent=180,tags='arc',style=ARC)
w.create_arc(-175,-30,-75,-130,extent=180,tags='leye')
w.create_arc(75,-30,175,-130,extent=180,tags='leye')
C = Cube(w)
mainloop()