Receita: Tkinter3dCanvas
Uma brincadeirinha... exibindo um cubo em 3D (wireframe) em um Canvas da Tkinter. A idéia era criar um método pra rotacionar coordenadas e poder passá-las diretamente para o Canvas, mas não funcionou muito bem. Nada muito útil, mas é interessante.
Código
1 #!/usr/bin/env python
2
3 from Tkinter import *
4 from math import *
5
6 class Cube(object):
7 def __init__(self, alpha=0, beta=0, gamma=0):
8 self._alpha = alpha
9 self._beta = beta
10 self._gamma = gamma
11
12 self.sin = [sin(alpha), sin(beta), sin(gamma)]
13 self.cos = [cos(alpha), cos(beta), cos(gamma)]
14 self.points = [[-1, -1, -1], [-1, -1, +1], [-1, +1, -1], [-1, +1, +1],
15 [+1, -1, -1], [+1, -1, +1], [+1, +1, -1], [+1, +1, +1]]
16
17
18
19 def __iter__(self):
20 lines = [(0, 1), (0, 2), (0, 4), (1, 3), (1, 5), (2, 3),
21 (2, 6), (3, 7), (4, 5), (4, 6), (5, 7), (6, 7)]
22
23 coords = ([self.points[i], self.points[j]] for i, j in lines)
24 return coords
25
26 coords = property(fget=__iter__)
27
28
29
30 def rotate(self, alpha=None, beta=None, gamma=None):
31 changed = False
32
33 if alpha is not None and alpha != self._alpha:
34 self.sin[0], self.cos[0] = sin(alpha), cos(alpha)
35 changed = True
36
37 if beta is not None and beta != self._beta:
38 self.sin[1], self.cos[1] = sin(beta), cos(beta)
39 changed = True
40
41 if gamma is not None and gamma != self._gamma:
42 self.sin[2], self.cos[2] = sin(gamma), cos(gamma)
43 changed = True
44
45 if changed:
46 points = [[-1, -1, -1], [-1, -1, +1], [-1, +1, -1], [-1, +1, +1],
47 [+1, -1, -1], [+1, -1, +1], [+1, +1, -1], [+1, +1, +1]]
48
49 self.points = map(self._rotate_point, points)
50
51 def _rotate_point(self, point):
52 x, y, z = point
53
54 sa, sb, sg = self.sin
55 ca, cb, cg = self.cos
56
57 x1 = z*sa + x*ca
58 y1 = y
59 z1 = z*ca - x*sa
60
61 x2 = x1
62 y2 = y1*cb - z1*sb
63 z2 = y1*sb + z1*cb
64
65 x3 = y2*sg + x2*cg
66 y3 = y2*cg - x2*sg
67 z3 = z2
68
69 return x3, y3, z3
70
71 def _set_alpha(self, alpha):
72 self.rotate(alpha=alpha)
73
74 alpha = property(fset=_set_alpha)
75
76 def _set_beta(self, beta):
77 self.rotate(beta=beta)
78
79 beta = property(fset=_set_beta)
80
81 def _set_gamma(self, gamma):
82 self.rotate(gamma=gamma)
83
84 gamma = property(fset=_set_gamma)
85
86
87
88 class MainWindow(Tk):
89 def __init__(self):
90 Tk.__init__(self)
91
92 width = 400
93 height = 400
94
95 self.canvas = Canvas(self, width=width, height=height, bg='white')
96 self.canvas.grid(row=0, column=1)
97
98 self.XOFF = XOFF = width/2
99 self.YOFF = YOFF = height/2
100 self.SCALE = 100.0
101
102 Scale(self, label='beta', from_=-180, to=180, resolution=1, orient=VERTICAL, command=self._set_beta).grid(row=0, column=0, sticky=N+S)
103 Scale(self, label='alpha', from_=-180, to=180, resolution=1, orient=HORIZONTAL, command=self._set_alpha).grid(row=1, column=1, sticky=W+E)
104 Scale(self, label='gamma', from_=-180, to=180, resolution=1, orient=HORIZONTAL, command=self._set_gamma).grid(row=2, column=1, sticky=W+E)
105
106 self.cube = Cube()
107
108 self.draw()
109
110 def draw(self):
111 S, X, Y = self.SCALE, self.XOFF, self.YOFF
112 self.lines = []
113 for line in self.cube:
114 line = [(point[0] * S + X, point[1] * S + Y) for point in line]
115 self.lines.append(self.canvas.create_line(line))
116
117 def _set_alpha(self, alpha):
118 alpha = radians(int(alpha))
119 self.cube.alpha = alpha
120 self.update_cube()
121
122 def _set_beta(self, beta):
123 beta = radians(int(beta))
124 self.cube.beta = beta
125 self.update_cube()
126
127 def _set_gamma(self, gamma):
128 gamma = radians(int(gamma))
129 self.cube.gamma = gamma
130 self.update_cube()
131
132 def update_cube(self):
133 S, X, Y = self.SCALE, self.XOFF, self.YOFF
134 for i, line in enumerate(self.cube):
135 line = [(point[0] * S + X, point[1] * S + Y) for point in line]
136 coords = []
137 [coords.extend(point) for point in line]
138 self.canvas.coords(self.lines[i], *coords)
139
140
141
142 if __name__ == "__main__":
143 root = MainWindow()
144 try:
145 root.mainloop()
146 except KeyboardInterrupt:
147 root.destroy()
Volta para CookBook.