0001 # LogoMation-like turtle graphics 0002 0003 from math import * # Also for export 0004 import Tkinter 0005 0006 class Error(Exception): 0007 pass 0008 0009 class RawPen: 0010 0011 def __init__(self, canvas): 0012 self._canvas = canvas 0013 self._items = [] 0014 self._tracing = 1 0015 self._arrow = 0 0016 self.degrees() 0017 self.reset() 0018 0019 def degrees(self, fullcircle=360.0): 0020 self._fullcircle = fullcircle 0021 self._invradian = pi / (fullcircle * 0.5) 0022 0023 def radians(self): 0024 self.degrees(2.0*pi) 0025 0026 def reset(self): 0027 canvas = self._canvas 0028 self._canvas.update() 0029 width = canvas.winfo_width() 0030 height = canvas.winfo_height() 0031 if width <= 1: 0032 width = canvas['width'] 0033 if height <= 1: 0034 height = canvas['height'] 0035 self._origin = float(width)/2.0, float(height)/2.0 0036 self._position = self._origin 0037 self._angle = 0.0 0038 self._drawing = 1 0039 self._width = 1 0040 self._color = "black" 0041 self._filling = 0 0042 self._path = [] 0043 self._tofill = [] 0044 self.clear() 0045 canvas._root().tkraise() 0046 0047 def clear(self): 0048 self.fill(0) 0049 canvas = self._canvas 0050 items = self._items 0051 self._items = [] 0052 for item in items: 0053 canvas.delete(item) 0054 self._delete_turtle() 0055 self._draw_turtle() 0056 0057 def tracer(self, flag): 0058 self._tracing = flag 0059 if not self._tracing: 0060 self._delete_turtle() 0061 self._draw_turtle() 0062 0063 def forward(self, distance): 0064 x0, y0 = start = self._position 0065 x1 = x0 + distance * cos(self._angle*self._invradian) 0066 y1 = y0 - distance * sin(self._angle*self._invradian) 0067 self._goto(x1, y1) 0068 0069 def backward(self, distance): 0070 self.forward(-distance) 0071 0072 def left(self, angle): 0073 self._angle = (self._angle + angle) % self._fullcircle 0074 self._draw_turtle() 0075 0076 def right(self, angle): 0077 self.left(-angle) 0078 0079 def up(self): 0080 self._drawing = 0 0081 0082 def down(self): 0083 self._drawing = 1 0084 0085 def width(self, width): 0086 self._width = float(width) 0087 0088 def color(self, *args): 0089 if not args: 0090 raise Error, "no color arguments" 0091 if len(args) == 1: 0092 color = args[0] 0093 if type(color) == type(""): 0094 # Test the color first 0095 try: 0096 id = self._canvas.create_line(0, 0, 0, 0, fill=color) 0097 except Tkinter.TclError: 0098 raise Error, "bad color string: %r" % (color,) 0099 self._set_color(color) 0100 return 0101 try: 0102 r, g, b = color 0103 except: 0104 raise Error, "bad color sequence: %r" % (color,) 0105 else: 0106 try: 0107 r, g, b = args 0108 except: 0109 raise Error, "bad color arguments: %r" % (args,) 0110 assert 0 <= r <= 1 0111 assert 0 <= g <= 1 0112 assert 0 <= b <= 1 0113 x = 255.0 0114 y = 0.5 0115 self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y))) 0116 0117 def _set_color(self,color): 0118 self._color = color 0119 self._draw_turtle() 0120 0121 def write(self, arg, move=0): 0122 x, y = start = self._position 0123 x = x-1 # correction -- calibrated for Windows 0124 item = self._canvas.create_text(x, y, 0125 text=str(arg), anchor="sw", 0126 fill=self._color) 0127 self._items.append(item) 0128 if move: 0129 x0, y0, x1, y1 = self._canvas.bbox(item) 0130 self._goto(x1, y1) 0131 self._draw_turtle() 0132 0133 def fill(self, flag): 0134 if self._filling: 0135 path = tuple(self._path) 0136 smooth = self._filling < 0 0137 if len(path) > 2: 0138 item = self._canvas._create('polygon', path, 0139 {'fill': self._color, 0140 'smooth': smooth}) 0141 self._items.append(item) 0142 self._canvas.lower(item) 0143 if self._tofill: 0144 for item in self._tofill: 0145 self._canvas.itemconfigure(item, fill=self._color) 0146 self._items.append(item) 0147 self._path = [] 0148 self._tofill = [] 0149 self._filling = flag 0150 if flag: 0151 self._path.append(self._position) 0152 self.forward(0) 0153 0154 def circle(self, radius, extent=None): 0155 if extent is None: 0156 extent = self._fullcircle 0157 x0, y0 = self._position 0158 xc = x0 - radius * sin(self._angle * self._invradian) 0159 yc = y0 - radius * cos(self._angle * self._invradian) 0160 if radius >= 0.0: 0161 start = self._angle - 90.0 0162 else: 0163 start = self._angle + 90.0 0164 extent = -extent 0165 if self._filling: 0166 if abs(extent) >= self._fullcircle: 0167 item = self._canvas.create_oval(xc-radius, yc-radius, 0168 xc+radius, yc+radius, 0169 width=self._width, 0170 outline="") 0171 self._tofill.append(item) 0172 item = self._canvas.create_arc(xc-radius, yc-radius, 0173 xc+radius, yc+radius, 0174 style="chord", 0175 start=start, 0176 extent=extent, 0177 width=self._width, 0178 outline="") 0179 self._tofill.append(item) 0180 if self._drawing: 0181 if abs(extent) >= self._fullcircle: 0182 item = self._canvas.create_oval(xc-radius, yc-radius, 0183 xc+radius, yc+radius, 0184 width=self._width, 0185 outline=self._color) 0186 self._items.append(item) 0187 item = self._canvas.create_arc(xc-radius, yc-radius, 0188 xc+radius, yc+radius, 0189 style="arc", 0190 start=start, 0191 extent=extent, 0192 width=self._width, 0193 outline=self._color) 0194 self._items.append(item) 0195 angle = start + extent 0196 x1 = xc + abs(radius) * cos(angle * self._invradian) 0197 y1 = yc - abs(radius) * sin(angle * self._invradian) 0198 self._angle = (self._angle + extent) % self._fullcircle 0199 self._position = x1, y1 0200 if self._filling: 0201 self._path.append(self._position) 0202 self._draw_turtle() 0203 0204 def heading(self): 0205 return self._angle 0206 0207 def setheading(self, angle): 0208 self._angle = angle 0209 self._draw_turtle() 0210 0211 def window_width(self): 0212 width = self._canvas.winfo_width() 0213 if width <= 1: # the window isn't managed by a geometry manager 0214 width = self._canvas['width'] 0215 return width 0216 0217 def window_height(self): 0218 height = self._canvas.winfo_height() 0219 if height <= 1: # the window isn't managed by a geometry manager 0220 height = self._canvas['height'] 0221 return height 0222 0223 def position(self): 0224 x0, y0 = self._origin 0225 x1, y1 = self._position 0226 return [x1-x0, -y1+y0] 0227 0228 def setx(self, xpos): 0229 x0, y0 = self._origin 0230 x1, y1 = self._position 0231 self._goto(x0+xpos, y1) 0232 0233 def sety(self, ypos): 0234 x0, y0 = self._origin 0235 x1, y1 = self._position 0236 self._goto(x1, y0-ypos) 0237 0238 def goto(self, *args): 0239 if len(args) == 1: 0240 try: 0241 x, y = args[0] 0242 except: 0243 raise Error, "bad point argument: %r" % (args[0],) 0244 else: 0245 try: 0246 x, y = args 0247 except: 0248 raise Error, "bad coordinates: %r" % (args[0],) 0249 x0, y0 = self._origin 0250 self._goto(x0+x, y0-y) 0251 0252 def _goto(self, x1, y1): 0253 x0, y0 = start = self._position 0254 self._position = map(float, (x1, y1)) 0255 if self._filling: 0256 self._path.append(self._position) 0257 if self._drawing: 0258 if self._tracing: 0259 dx = float(x1 - x0) 0260 dy = float(y1 - y0) 0261 distance = hypot(dx, dy) 0262 nhops = int(distance) 0263 item = self._canvas.create_line(x0, y0, x0, y0, 0264 width=self._width, 0265 capstyle="round", 0266 fill=self._color) 0267 try: 0268 for i in range(1, 1+nhops): 0269 x, y = x0 + dx*i/nhops, y0 + dy*i/nhops 0270 self._canvas.coords(item, x0, y0, x, y) 0271 self._draw_turtle((x,y)) 0272 self._canvas.update() 0273 self._canvas.after(10) 0274 # in case nhops==0 0275 self._canvas.coords(item, x0, y0, x1, y1) 0276 self._canvas.itemconfigure(item, arrow="none") 0277 except Tkinter.TclError: 0278 # Probably the window was closed! 0279 return 0280 else: 0281 item = self._canvas.create_line(x0, y0, x1, y1, 0282 width=self._width, 0283 capstyle="round", 0284 fill=self._color) 0285 self._items.append(item) 0286 self._draw_turtle() 0287 0288 def _draw_turtle(self,position=[]): 0289 if not self._tracing: 0290 return 0291 if position == []: 0292 position = self._position 0293 x,y = position 0294 distance = 8 0295 dx = distance * cos(self._angle*self._invradian) 0296 dy = distance * sin(self._angle*self._invradian) 0297 self._delete_turtle() 0298 self._arrow = self._canvas.create_line(x-dx,y+dy,x,y, 0299 width=self._width, 0300 arrow="last", 0301 capstyle="round", 0302 fill=self._color) 0303 self._canvas.update() 0304 0305 def _delete_turtle(self): 0306 if self._arrow != 0: 0307 self._canvas.delete(self._arrow) 0308 self._arrow = 0 0309 0310 0311 0312 _root = None 0313 _canvas = None 0314 _pen = None 0315 0316 class Pen(RawPen): 0317 0318 def __init__(self): 0319 global _root, _canvas 0320 if _root is None: 0321 _root = Tkinter.Tk() 0322 _root.wm_protocol("WM_DELETE_WINDOW", self._destroy) 0323 if _canvas is None: 0324 # XXX Should have scroll bars 0325 _canvas = Tkinter.Canvas(_root, background="white") 0326 _canvas.pack(expand=1, fill="both") 0327 RawPen.__init__(self, _canvas) 0328 0329 def _destroy(self): 0330 global _root, _canvas, _pen 0331 root = self._canvas._root() 0332 if root is _root: 0333 _pen = None 0334 _root = None 0335 _canvas = None 0336 root.destroy() 0337 0338 0339 def _getpen(): 0340 global _pen 0341 pen = _pen 0342 if not pen: 0343 _pen = pen = Pen() 0344 return pen 0345 0346 def degrees(): _getpen().degrees() 0347 def radians(): _getpen().radians() 0348 def reset(): _getpen().reset() 0349 def clear(): _getpen().clear() 0350 def tracer(flag): _getpen().tracer(flag) 0351 def forward(distance): _getpen().forward(distance) 0352 def backward(distance): _getpen().backward(distance) 0353 def left(angle): _getpen().left(angle) 0354 def right(angle): _getpen().right(angle) 0355 def up(): _getpen().up() 0356 def down(): _getpen().down() 0357 def width(width): _getpen().width(width) 0358 def color(*args): _getpen().color(*args) 0359 def write(arg, move=0): _getpen().write(arg, move) 0360 def fill(flag): _getpen().fill(flag) 0361 def circle(radius, extent=None): _getpen().circle(radius, extent) 0362 def goto(*args): _getpen().goto(*args) 0363 def heading(): return _getpen().heading() 0364 def setheading(angle): _getpen().setheading(angle) 0365 def position(): return _getpen().position() 0366 def window_width(): return _getpen().window_width() 0367 def window_height(): return _getpen().window_height() 0368 def setx(xpos): _getpen().setx(xpos) 0369 def sety(ypos): _getpen().sety(ypos) 0370 0371 def demo(): 0372 reset() 0373 tracer(1) 0374 up() 0375 backward(100) 0376 down() 0377 # draw 3 squares; the last filled 0378 width(3) 0379 for i in range(3): 0380 if i == 2: 0381 fill(1) 0382 for j in range(4): 0383 forward(20) 0384 left(90) 0385 if i == 2: 0386 color("maroon") 0387 fill(0) 0388 up() 0389 forward(30) 0390 down() 0391 width(1) 0392 color("black") 0393 # move out of the way 0394 tracer(0) 0395 up() 0396 right(90) 0397 forward(100) 0398 right(90) 0399 forward(100) 0400 right(180) 0401 down() 0402 # some text 0403 write("startstart", 1) 0404 write("start", 1) 0405 color("red") 0406 # staircase 0407 for i in range(5): 0408 forward(20) 0409 left(90) 0410 forward(20) 0411 right(90) 0412 # filled staircase 0413 fill(1) 0414 for i in range(5): 0415 forward(20) 0416 left(90) 0417 forward(20) 0418 right(90) 0419 fill(0) 0420 # more text 0421 write("end") 0422 if __name__ == '__main__': 0423 _root.mainloop() 0424 0425 if __name__ == '__main__': 0426 demo() 0427
Generated by PyXR 0.9.4