Just for fun I stole some of the turtle code, added docstrings, used
complex as position format, and made a small (but not entirely minimal)
turtle class. I figured this might do as a straw-man for Myrtle the
Minimal Turtle. I do like Christian Mascher's idea of making a turtle
with a contained Pen being how to control all of the "dir()" results.
--Scott David Daniels
[EMAIL PROTECTED]
# $Id: myrtle.py 1.3 2006/03/04 22:54:25 daniels Exp daniels $
'''Myrtle the minimally complex turtle'''
from math import sin, cos, tan, pi, atan2
import Tkinter
__version__ = '0.3'
__all__ = 'Turtle pi'.split()
class Turtle(object):
_root = None
_canvas = None
def destroy(self):
'''Wipe out evidence of where the root and canvas are'''
root = self.canvas._root()
if root is self._root:
self.__class__._root = None
self.__class__._canvas = self.canvas = None
root.destroy()
def __init__(self, canvas=None, root=None):
'''Make a turtle, and a canvas pen for it to play in (if necessary)'''
# Make a canvas (and a root) if necessary, record root.
if canvas is None:
if root is None:
if self.__class__._root is None:
self.__class__._root = root = Tkinter.Tk()
root.wm_protocol("WM_DELETE_WINDOW", self.destroy)
root = self.__class__._root
if self.__class__._canvas is None:
canvas = Tkinter.Canvas(root, background="white")
canvas.pack(expand=1, fill="both")
self.__class__._canvas = canvas
canvas = self.__class__._canvas
elif self.__class__._root is None:
if root is None:
root = canvas._root()
self.__class__._root = root
self.canvas = canvas # The canvas playpen for our turtle
self.items = [] # things showing on canvas
self.tracing = True # moving in little increments
self.arrow = 0 # The visible manifextation of the Turtle
self.reset() # Set other things up
def reset(self):
'''Erase the canvas and place the turtle in the center'''
self.canvas.update() # Make sure canvas is up-to-date
# Find current window sizes, and set origin and position at center
self.position = self.origin = self.window_dimension() * .5
# Set step-scaling and direction to right, 8 pixels
self.heading = complex(8.)
self.drawing = True # False for Pen-Up operation
self.width = 1 # width of the line the turtle leaves behind
self.ink = "black" # color of ink Turtle currently wielding
self.filling = 0 # polygon (1), smooth (-1), or non-fill modes
self.path = [] # Track of positions for use by fill modes
self.clear()
self.canvas._root().tkraise() # Pop turtle's canvas to top-o-screen
def window_dimension(self):
'''Get the width and height of the canvas'''
width = self.canvas.winfo_width()
if width <= 1: # the window isn't managed by a geometry manager
width = self.canvas['width']
height = self.canvas.winfo_height()
if height <= 1: # the window isn't managed by a geometry manager
height = self.canvas['height']
return complex(width, height)
def clear(self):
'''Drop all known elements from the canvas'''
self.fill(False)
for item in self.items:
self.canvas.delete(item)
self.items = []
self.hide()
self.show()
def fill(self, flag):
'''Fill path so far, then 0: no fill, 1: polygon fill, -1: smooth
fill'''
if self.filling:
if len(self.path) > 2:
# can't create filled anything with less than 2 points
path = [(p.real, p.imag) for p in self.path]
item = self.canvas._create('polygon', path,
dict(fill=self.ink,
smooth=self.filling < 0))
self.items.append(item)
self.canvas.lower(item)
self.path = []
self.filling = flag
if flag:
self.path.append(self.position)
self.forward(0)
def show(self, position=None):
'''Make the turtle visible (if tracing)'''
if self.tracing:
if position is None:
position = self.position
back = position - 2 * self.heading
self.hide()
self.arrow = self.canvas.create_line(back.real, back.imag,
position.real, position.imag,
width=self.width,
arrow="last",
capstyle="round",
fill=self.ink)
self.canvas.update()
def hide(self):
'''Make the turtle invisible'''
if self.arrow:
self.canvas.delete(self.arrow)
self.arrow = 0
def forward(self, distance=1):
'''Move forward'''
self.goto(self.position + distance * self.heading)
def left(self, angle=pi/2):
'''Rotate left angle radians.'''
dist = abs(self.heading)
angle += atan2(self.heading.real, self.heading.imag)
self.heading = abs(self.heading) * complex(sin(angle), cos(angle))
if self.tracing:
self.show()
def goto(self, destination):
'''Move the turtle to the destination.'''
start = self.position
self.position = destination
if self.filling:
self.path.append(self.position)
if self.drawing:
if self.tracing:
delta = destination - start
hops = int(abs(delta))
item = self.canvas.create_line(start.real, start.imag,
start.real, start.imag,
width=self.width,
capstyle="round",
fill=self.ink)
try:
for i in range(1, hops):
pos = start + delta * i / hops
self.canvas.coords(item,
start.real, start.imag,
pos.real, pos.imag)
self.show(pos)
self.canvas.update()
self.canvas.after(10)
self.canvas.coords(item, start.real, start.imag,
destination.real, destination.imag)
self.canvas.itemconfigure(item, arrow="none")
except Tkinter.TclError:
# Probably the window was closed!
return
else:
item = self.canvas.create_line(start.real, start.imag,
destination.real, destination.imag,
width=self.width,
capstyle="round",
fill=self.ink)
self.items.append(item)
self.show()
def write(self, text, move=False):
'''Write text at the current position. If move True, position past
it.'''
x = self.position.real - 1 # correction -- calibrated for Windows
y = self.position.imag
if not isinstance(text, basestring): text = str(text)
item = self.canvas.create_text(x, y,
text=text, anchor="sw",
fill=self.ink)
self.items.append(item)
if move:
x0, y0, x1, y1 = self.canvas.bbox(item)
self.goto(complex(x1, y1))
self.show()
def color(self, *args):
'''Set my ink color (name or r,g,b where 1,1,1 is pure white)'''
if not args:
raise Error, "no color arguments"
if len(args) == 1:
color = args[0]
if isinstance(color, basestring):
# Test the color first
try:
id = self._canvas.create_line(0, 0, 0, 0, fill=color)
except Tkinter.TclError:
raise Error, "bad color string: %r" % (color,)
self._set_color(color)
return
try:
r, g, b = color
except:
raise Error, "bad color sequence: %r" % (color,)
else:
try:
r, g, b = args
except:
raise Error, "bad color arguments: %r" % (args,)
assert 0 <= r <= 1 and 0 <= g <= 1 and 0 <= b <= 1
x = 255.0
y = 0.5
self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))
def _set_color(self, color):
'''Set ink color by name only (for internal use)'''
self.ink = color
self.show()
_______________________________________________
Edu-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/edu-sig