Tkinter3dCanvas

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.


PedroWerneck

Tkinter3dCanvas (editada pela última vez em 2008-09-26 14:07:15 por localhost)