mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	than a pixel don't get drawn at all. If you're building long curves made of such lines, this is a bad thing.
		
			
				
	
	
		
			345 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			345 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# LogoMation-like turtle graphics
 | 
						|
 | 
						|
from math import * # Also for export
 | 
						|
import Tkinter
 | 
						|
class Error(Exception):
 | 
						|
    pass
 | 
						|
 | 
						|
class RawPen:
 | 
						|
 | 
						|
    def __init__(self, canvas):
 | 
						|
        self._canvas = canvas
 | 
						|
        self._items = []
 | 
						|
        self._tracing = 1
 | 
						|
        self.degrees()
 | 
						|
        self.reset()
 | 
						|
 | 
						|
    def degrees(self, fullcircle=360.0):
 | 
						|
        self._fullcircle = fullcircle
 | 
						|
        self._invradian = pi / (fullcircle * 0.5)
 | 
						|
 | 
						|
    def radians(self):
 | 
						|
        self.degrees(2.0*pi)
 | 
						|
 | 
						|
    def reset(self):
 | 
						|
        canvas = self._canvas
 | 
						|
        width = canvas.winfo_width()
 | 
						|
        height = canvas.winfo_height()
 | 
						|
        if width <= 1:
 | 
						|
            width = canvas['width']
 | 
						|
        if height <= 1:
 | 
						|
            height = canvas['height']
 | 
						|
        self._origin = float(width)/2.0, float(height)/2.0
 | 
						|
        self._position = self._origin
 | 
						|
        self._angle = 0.0
 | 
						|
        self._drawing = 1
 | 
						|
        self._width = 1
 | 
						|
        self._color = "black"
 | 
						|
        self._filling = 0
 | 
						|
        self._path = []
 | 
						|
        self._tofill = []
 | 
						|
        self.clear()
 | 
						|
        canvas._root().tkraise()
 | 
						|
 | 
						|
    def clear(self):
 | 
						|
        self.fill(0)
 | 
						|
        canvas = self._canvas
 | 
						|
        items = self._items
 | 
						|
        self._items = []
 | 
						|
        for item in items:
 | 
						|
            canvas.delete(item)
 | 
						|
 | 
						|
    def tracer(self, flag):
 | 
						|
        self._tracing = flag
 | 
						|
 | 
						|
    def forward(self, distance):
 | 
						|
        x0, y0 = start = self._position
 | 
						|
        x1 = x0 + distance * cos(self._angle*self._invradian)
 | 
						|
        y1 = y0 - distance * sin(self._angle*self._invradian)
 | 
						|
        self._goto(x1, y1)
 | 
						|
 | 
						|
    def backward(self, distance):
 | 
						|
        self.forward(-distance)
 | 
						|
 | 
						|
    def left(self, angle):
 | 
						|
        self._angle = (self._angle + angle) % self._fullcircle
 | 
						|
 | 
						|
    def right(self, angle):
 | 
						|
        self.left(-angle)
 | 
						|
 | 
						|
    def up(self):
 | 
						|
        self._drawing = 0
 | 
						|
 | 
						|
    def down(self):
 | 
						|
        self._drawing = 1
 | 
						|
 | 
						|
    def width(self, width):
 | 
						|
        self._width = float(width)
 | 
						|
 | 
						|
    def color(self, *args):
 | 
						|
        if not args:
 | 
						|
            raise Error, "no color arguments"
 | 
						|
        if len(args) == 1:
 | 
						|
            color = args[0]
 | 
						|
            if type(color) == type(""):
 | 
						|
                # Test the color first
 | 
						|
                try:
 | 
						|
                    id = self._canvas.create_line(0, 0, 0, 0, fill=color)
 | 
						|
                except Tkinter.TclError:
 | 
						|
                    raise Error, "bad color string: %s" % `color`
 | 
						|
                self._color = color
 | 
						|
                return
 | 
						|
            try:
 | 
						|
                r, g, b = color
 | 
						|
            except:
 | 
						|
                raise Error, "bad color sequence: %s" % `color`
 | 
						|
        else:
 | 
						|
            try:
 | 
						|
                r, g, b = args
 | 
						|
            except:
 | 
						|
                raise Error, "bad color arguments: %s" % `args`
 | 
						|
        assert 0 <= r <= 1
 | 
						|
        assert 0 <= g <= 1
 | 
						|
        assert 0 <= b <= 1
 | 
						|
        x = 255.0
 | 
						|
        y = 0.5
 | 
						|
        self._color = "#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y))
 | 
						|
 | 
						|
    def write(self, arg, move=0):
 | 
						|
        x, y = start = self._position
 | 
						|
        x = x-1 # correction -- calibrated for Windows
 | 
						|
        item = self._canvas.create_text(x, y,
 | 
						|
                                        text=str(arg), anchor="sw",
 | 
						|
                                        fill=self._color)
 | 
						|
        self._items.append(item)
 | 
						|
        if move:
 | 
						|
            x0, y0, x1, y1 = self._canvas.bbox(item)
 | 
						|
            self._goto(x1, y1)
 | 
						|
 | 
						|
    def fill(self, flag):
 | 
						|
        if self._filling:
 | 
						|
            path = tuple(self._path)
 | 
						|
            smooth = self._filling < 0
 | 
						|
            if len(path) > 2:
 | 
						|
                item = self._canvas._create('polygon', path,
 | 
						|
                                            {'fill': self._color,
 | 
						|
                                             'smooth': smooth})
 | 
						|
                self._items.append(item)
 | 
						|
                self._canvas.lower(item)
 | 
						|
                if self._tofill:
 | 
						|
                    for item in self._tofill:
 | 
						|
                        self._canvas.itemconfigure(item, fill=self._color)
 | 
						|
                        self._items.append(item)
 | 
						|
        self._path = []
 | 
						|
        self._tofill = []
 | 
						|
        self._filling = flag
 | 
						|
        if flag:
 | 
						|
            self._path.append(self._position)
 | 
						|
 | 
						|
    def circle(self, radius, extent=None):
 | 
						|
        if extent is None:
 | 
						|
            extent = self._fullcircle
 | 
						|
        x0, y0 = self._position
 | 
						|
        xc = x0 - radius * sin(self._angle * self._invradian)
 | 
						|
        yc = y0 - radius * cos(self._angle * self._invradian)
 | 
						|
        if radius >= 0.0:
 | 
						|
            start = self._angle - 90.0
 | 
						|
        else:
 | 
						|
            start = self._angle + 90.0
 | 
						|
            extent = -extent
 | 
						|
        if self._filling:
 | 
						|
            if abs(extent) >= self._fullcircle:
 | 
						|
                item = self._canvas.create_oval(xc-radius, yc-radius,
 | 
						|
                                                xc+radius, yc+radius,
 | 
						|
                                                width=self._width,
 | 
						|
                                                outline="")
 | 
						|
                self._tofill.append(item)
 | 
						|
            item = self._canvas.create_arc(xc-radius, yc-radius,
 | 
						|
                                           xc+radius, yc+radius,
 | 
						|
                                           style="chord",
 | 
						|
                                           start=start,
 | 
						|
                                           extent=extent,
 | 
						|
                                           width=self._width,
 | 
						|
                                           outline="")
 | 
						|
            self._tofill.append(item)
 | 
						|
        if self._drawing:
 | 
						|
            if abs(extent) >= self._fullcircle:
 | 
						|
                item = self._canvas.create_oval(xc-radius, yc-radius,
 | 
						|
                                                xc+radius, yc+radius,
 | 
						|
                                                width=self._width,
 | 
						|
                                                outline=self._color)
 | 
						|
                self._items.append(item)
 | 
						|
            item = self._canvas.create_arc(xc-radius, yc-radius,
 | 
						|
                                           xc+radius, yc+radius,
 | 
						|
                                           style="arc",
 | 
						|
                                           start=start,
 | 
						|
                                           extent=extent,
 | 
						|
                                           width=self._width,
 | 
						|
                                           outline=self._color)
 | 
						|
            self._items.append(item)
 | 
						|
        angle = start + extent
 | 
						|
        x1 = xc + abs(radius) * cos(angle * self._invradian)
 | 
						|
        y1 = yc - abs(radius) * sin(angle * self._invradian)
 | 
						|
        self._angle = (self._angle + extent) % self._fullcircle
 | 
						|
        self._position = x1, y1
 | 
						|
        if self._filling:
 | 
						|
            self._path.append(self._position)
 | 
						|
 | 
						|
    def goto(self, *args):
 | 
						|
        if len(args) == 1:
 | 
						|
            try:
 | 
						|
                x, y = args[0]
 | 
						|
            except:
 | 
						|
                raise Error, "bad point argument: %s" % `args[0]`
 | 
						|
        else:
 | 
						|
            try:
 | 
						|
                x, y = args
 | 
						|
            except:
 | 
						|
                raise Error, "bad coordinates: %s" % `args[0]`
 | 
						|
        x0, y0 = self._origin
 | 
						|
        self._goto(x0+x, y0-y)
 | 
						|
 | 
						|
    def _goto(self, x1, y1):
 | 
						|
        x0, y0 = start = self._position
 | 
						|
        self._position = map(float, (x1, y1))
 | 
						|
        if self._filling:
 | 
						|
            self._path.append(self._position)
 | 
						|
        if self._drawing:
 | 
						|
            if self._tracing:
 | 
						|
                dx = float(x1 - x0)
 | 
						|
                dy = float(y1 - y0)
 | 
						|
                distance = hypot(dx, dy)
 | 
						|
                nhops = int(distance)
 | 
						|
                item = self._canvas.create_line(x0, y0, x0, y0,
 | 
						|
                                                width=self._width,
 | 
						|
                                                arrow="last",
 | 
						|
                                                capstyle="round",
 | 
						|
                                                fill=self._color)
 | 
						|
                try:
 | 
						|
                    for i in range(1, 1+nhops):
 | 
						|
                        x, y = x0 + dx*i/nhops, y0 + dy*i/nhops
 | 
						|
                        self._canvas.coords(item, x0, y0, x, y)
 | 
						|
                        self._canvas.update()
 | 
						|
                        self._canvas.after(10)
 | 
						|
                    # in case nhops==0
 | 
						|
                    self._canvas.coords(item, x0, y0, x1, y1)
 | 
						|
                    self._canvas.itemconfigure(item, arrow="none")
 | 
						|
                except Tkinter.TclError:
 | 
						|
                    # Probably the window was closed!
 | 
						|
                    return
 | 
						|
            else:
 | 
						|
                item = self._canvas.create_line(x0, y0, x1, y1,
 | 
						|
                                                width=self._width,
 | 
						|
                                                capstyle="round",
 | 
						|
                                                fill=self._color)
 | 
						|
            self._items.append(item)
 | 
						|
 | 
						|
 | 
						|
_root = None
 | 
						|
_canvas = None
 | 
						|
_pen = None
 | 
						|
 | 
						|
class Pen(RawPen):
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        global _root, _canvas
 | 
						|
        if _root is None:
 | 
						|
            _root = Tkinter.Tk()
 | 
						|
            _root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
 | 
						|
        if _canvas is None:
 | 
						|
            # XXX Should have scroll bars
 | 
						|
            _canvas = Tkinter.Canvas(_root, background="white")
 | 
						|
            _canvas.pack(expand=1, fill="both")
 | 
						|
        RawPen.__init__(self, _canvas)
 | 
						|
 | 
						|
    def _destroy(self):
 | 
						|
        global _root, _canvas, _pen
 | 
						|
        root = self._canvas._root()
 | 
						|
        if root is _root:
 | 
						|
            _pen = None
 | 
						|
            _root = None
 | 
						|
            _canvas = None
 | 
						|
        root.destroy()
 | 
						|
 | 
						|
 | 
						|
def _getpen():
 | 
						|
    global _pen
 | 
						|
    pen = _pen
 | 
						|
    if not pen:
 | 
						|
        _pen = pen = Pen()
 | 
						|
    return pen
 | 
						|
 | 
						|
def degrees(): _getpen().degrees()
 | 
						|
def radians(): _getpen().radians()
 | 
						|
def reset(): _getpen().reset()
 | 
						|
def clear(): _getpen().clear()
 | 
						|
def tracer(flag): _getpen().tracer(flag)
 | 
						|
def forward(distance): _getpen().forward(distance)
 | 
						|
def backward(distance): _getpen().backward(distance)
 | 
						|
def left(angle): _getpen().left(angle)
 | 
						|
def right(angle): _getpen().right(angle)
 | 
						|
def up(): _getpen().up()
 | 
						|
def down(): _getpen().down()
 | 
						|
def width(width): _getpen().width(width)
 | 
						|
def color(*args): apply(_getpen().color, args)
 | 
						|
def write(arg, move=0): _getpen().write(arg, move)
 | 
						|
def fill(flag): _getpen().fill(flag)
 | 
						|
def circle(radius, extent=None): _getpen().circle(radius, extent)
 | 
						|
def goto(*args): apply(_getpen().goto, args)
 | 
						|
 | 
						|
def demo():
 | 
						|
    reset()
 | 
						|
    tracer(1)
 | 
						|
    up()
 | 
						|
    backward(100)
 | 
						|
    down()
 | 
						|
    # draw 3 squares; the last filled
 | 
						|
    width(3)
 | 
						|
    for i in range(3):
 | 
						|
        if i == 2:
 | 
						|
            fill(1)
 | 
						|
        for j in range(4):
 | 
						|
            forward(20)
 | 
						|
            left(90)
 | 
						|
        if i == 2:
 | 
						|
            color("maroon")
 | 
						|
            fill(0)
 | 
						|
        up()
 | 
						|
        forward(30)
 | 
						|
        down()
 | 
						|
    width(1)
 | 
						|
    color("black")
 | 
						|
    # move out of the way
 | 
						|
    tracer(0)
 | 
						|
    up()
 | 
						|
    right(90)
 | 
						|
    forward(100)
 | 
						|
    right(90)
 | 
						|
    forward(100)
 | 
						|
    right(180)
 | 
						|
    down()
 | 
						|
    # some text
 | 
						|
    write("startstart", 1)
 | 
						|
    write("start", 1)
 | 
						|
    color("red")
 | 
						|
    # staircase
 | 
						|
    for i in range(5):
 | 
						|
        forward(20)
 | 
						|
        left(90)
 | 
						|
        forward(20)
 | 
						|
        right(90)
 | 
						|
    # filled staircase
 | 
						|
    fill(1)
 | 
						|
    for i in range(5):
 | 
						|
        forward(20)
 | 
						|
        left(90)
 | 
						|
        forward(20)
 | 
						|
        right(90)
 | 
						|
    fill(0)
 | 
						|
    # more text
 | 
						|
    write("end")
 | 
						|
    if __name__ == '__main__':
 | 
						|
        _root.mainloop()
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    demo()
 |