|
1 # LogoMation-like turtle graphics |
|
2 |
|
3 """ |
|
4 Turtle graphics is a popular way for introducing programming to |
|
5 kids. It was part of the original Logo programming language developed |
|
6 by Wally Feurzeig and Seymour Papert in 1966. |
|
7 |
|
8 Imagine a robotic turtle starting at (0, 0) in the x-y plane. Give it |
|
9 the command turtle.forward(15), and it moves (on-screen!) 15 pixels in |
|
10 the direction it is facing, drawing a line as it moves. Give it the |
|
11 command turtle.left(25), and it rotates in-place 25 degrees clockwise. |
|
12 |
|
13 By combining together these and similar commands, intricate shapes and |
|
14 pictures can easily be drawn. |
|
15 """ |
|
16 |
|
17 from math import * # Also for export |
|
18 from time import sleep |
|
19 import Tkinter |
|
20 |
|
21 speeds = ['fastest', 'fast', 'normal', 'slow', 'slowest'] |
|
22 |
|
23 class Error(Exception): |
|
24 pass |
|
25 |
|
26 class RawPen: |
|
27 |
|
28 def __init__(self, canvas): |
|
29 self._canvas = canvas |
|
30 self._items = [] |
|
31 self._tracing = 1 |
|
32 self._arrow = 0 |
|
33 self._delay = 10 # default delay for drawing |
|
34 self._angle = 0.0 |
|
35 self.degrees() |
|
36 self.reset() |
|
37 |
|
38 def degrees(self, fullcircle=360.0): |
|
39 """ Set angle measurement units to degrees. |
|
40 |
|
41 Example: |
|
42 >>> turtle.degrees() |
|
43 """ |
|
44 # Don't try to change _angle if it is 0, because |
|
45 # _fullcircle might not be set, yet |
|
46 if self._angle: |
|
47 self._angle = (self._angle / self._fullcircle) * fullcircle |
|
48 self._fullcircle = fullcircle |
|
49 self._invradian = pi / (fullcircle * 0.5) |
|
50 |
|
51 def radians(self): |
|
52 """ Set the angle measurement units to radians. |
|
53 |
|
54 Example: |
|
55 >>> turtle.radians() |
|
56 """ |
|
57 self.degrees(2.0*pi) |
|
58 |
|
59 def reset(self): |
|
60 """ Clear the screen, re-center the pen, and set variables to |
|
61 the default values. |
|
62 |
|
63 Example: |
|
64 >>> turtle.position() |
|
65 [0.0, -22.0] |
|
66 >>> turtle.heading() |
|
67 100.0 |
|
68 >>> turtle.reset() |
|
69 >>> turtle.position() |
|
70 [0.0, 0.0] |
|
71 >>> turtle.heading() |
|
72 0.0 |
|
73 """ |
|
74 canvas = self._canvas |
|
75 self._canvas.update() |
|
76 width = canvas.winfo_width() |
|
77 height = canvas.winfo_height() |
|
78 if width <= 1: |
|
79 width = canvas['width'] |
|
80 if height <= 1: |
|
81 height = canvas['height'] |
|
82 self._origin = float(width)/2.0, float(height)/2.0 |
|
83 self._position = self._origin |
|
84 self._angle = 0.0 |
|
85 self._drawing = 1 |
|
86 self._width = 1 |
|
87 self._color = "black" |
|
88 self._filling = 0 |
|
89 self._path = [] |
|
90 self.clear() |
|
91 canvas._root().tkraise() |
|
92 |
|
93 def clear(self): |
|
94 """ Clear the screen. The turtle does not move. |
|
95 |
|
96 Example: |
|
97 >>> turtle.clear() |
|
98 """ |
|
99 self.fill(0) |
|
100 canvas = self._canvas |
|
101 items = self._items |
|
102 self._items = [] |
|
103 for item in items: |
|
104 canvas.delete(item) |
|
105 self._delete_turtle() |
|
106 self._draw_turtle() |
|
107 |
|
108 def tracer(self, flag): |
|
109 """ Set tracing on if flag is True, and off if it is False. |
|
110 Tracing means line are drawn more slowly, with an |
|
111 animation of an arrow along the line. |
|
112 |
|
113 Example: |
|
114 >>> turtle.tracer(False) # turns off Tracer |
|
115 """ |
|
116 self._tracing = flag |
|
117 if not self._tracing: |
|
118 self._delete_turtle() |
|
119 self._draw_turtle() |
|
120 |
|
121 def forward(self, distance): |
|
122 """ Go forward distance steps. |
|
123 |
|
124 Example: |
|
125 >>> turtle.position() |
|
126 [0.0, 0.0] |
|
127 >>> turtle.forward(25) |
|
128 >>> turtle.position() |
|
129 [25.0, 0.0] |
|
130 >>> turtle.forward(-75) |
|
131 >>> turtle.position() |
|
132 [-50.0, 0.0] |
|
133 """ |
|
134 x0, y0 = start = self._position |
|
135 x1 = x0 + distance * cos(self._angle*self._invradian) |
|
136 y1 = y0 - distance * sin(self._angle*self._invradian) |
|
137 self._goto(x1, y1) |
|
138 |
|
139 def backward(self, distance): |
|
140 """ Go backwards distance steps. |
|
141 |
|
142 The turtle's heading does not change. |
|
143 |
|
144 Example: |
|
145 >>> turtle.position() |
|
146 [0.0, 0.0] |
|
147 >>> turtle.backward(30) |
|
148 >>> turtle.position() |
|
149 [-30.0, 0.0] |
|
150 """ |
|
151 self.forward(-distance) |
|
152 |
|
153 def left(self, angle): |
|
154 """ Turn left angle units (units are by default degrees, |
|
155 but can be set via the degrees() and radians() functions.) |
|
156 |
|
157 When viewed from above, the turning happens in-place around |
|
158 its front tip. |
|
159 |
|
160 Example: |
|
161 >>> turtle.heading() |
|
162 22 |
|
163 >>> turtle.left(45) |
|
164 >>> turtle.heading() |
|
165 67.0 |
|
166 """ |
|
167 self._angle = (self._angle + angle) % self._fullcircle |
|
168 self._draw_turtle() |
|
169 |
|
170 def right(self, angle): |
|
171 """ Turn right angle units (units are by default degrees, |
|
172 but can be set via the degrees() and radians() functions.) |
|
173 |
|
174 When viewed from above, the turning happens in-place around |
|
175 its front tip. |
|
176 |
|
177 Example: |
|
178 >>> turtle.heading() |
|
179 22 |
|
180 >>> turtle.right(45) |
|
181 >>> turtle.heading() |
|
182 337.0 |
|
183 """ |
|
184 self.left(-angle) |
|
185 |
|
186 def up(self): |
|
187 """ Pull the pen up -- no drawing when moving. |
|
188 |
|
189 Example: |
|
190 >>> turtle.up() |
|
191 """ |
|
192 self._drawing = 0 |
|
193 |
|
194 def down(self): |
|
195 """ Put the pen down -- draw when moving. |
|
196 |
|
197 Example: |
|
198 >>> turtle.down() |
|
199 """ |
|
200 self._drawing = 1 |
|
201 |
|
202 def width(self, width): |
|
203 """ Set the line to thickness to width. |
|
204 |
|
205 Example: |
|
206 >>> turtle.width(10) |
|
207 """ |
|
208 self._width = float(width) |
|
209 |
|
210 def color(self, *args): |
|
211 """ Set the pen color. |
|
212 |
|
213 Three input formats are allowed: |
|
214 |
|
215 color(s) |
|
216 s is a Tk specification string, such as "red" or "yellow" |
|
217 |
|
218 color((r, g, b)) |
|
219 *a tuple* of r, g, and b, which represent, an RGB color, |
|
220 and each of r, g, and b are in the range [0..1] |
|
221 |
|
222 color(r, g, b) |
|
223 r, g, and b represent an RGB color, and each of r, g, and b |
|
224 are in the range [0..1] |
|
225 |
|
226 Example: |
|
227 |
|
228 >>> turtle.color('brown') |
|
229 >>> tup = (0.2, 0.8, 0.55) |
|
230 >>> turtle.color(tup) |
|
231 >>> turtle.color(0, .5, 0) |
|
232 """ |
|
233 if not args: |
|
234 raise Error, "no color arguments" |
|
235 if len(args) == 1: |
|
236 color = args[0] |
|
237 if type(color) == type(""): |
|
238 # Test the color first |
|
239 try: |
|
240 id = self._canvas.create_line(0, 0, 0, 0, fill=color) |
|
241 except Tkinter.TclError: |
|
242 raise Error, "bad color string: %r" % (color,) |
|
243 self._set_color(color) |
|
244 return |
|
245 try: |
|
246 r, g, b = color |
|
247 except: |
|
248 raise Error, "bad color sequence: %r" % (color,) |
|
249 else: |
|
250 try: |
|
251 r, g, b = args |
|
252 except: |
|
253 raise Error, "bad color arguments: %r" % (args,) |
|
254 assert 0 <= r <= 1 |
|
255 assert 0 <= g <= 1 |
|
256 assert 0 <= b <= 1 |
|
257 x = 255.0 |
|
258 y = 0.5 |
|
259 self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y))) |
|
260 |
|
261 def _set_color(self,color): |
|
262 self._color = color |
|
263 self._draw_turtle() |
|
264 |
|
265 def write(self, text, move=False): |
|
266 """ Write text at the current pen position. |
|
267 |
|
268 If move is true, the pen is moved to the bottom-right corner |
|
269 of the text. By default, move is False. |
|
270 |
|
271 Example: |
|
272 >>> turtle.write('The race is on!') |
|
273 >>> turtle.write('Home = (0, 0)', True) |
|
274 """ |
|
275 x, y = self._position |
|
276 x = x-1 # correction -- calibrated for Windows |
|
277 item = self._canvas.create_text(x, y, |
|
278 text=str(text), anchor="sw", |
|
279 fill=self._color) |
|
280 self._items.append(item) |
|
281 if move: |
|
282 x0, y0, x1, y1 = self._canvas.bbox(item) |
|
283 self._goto(x1, y1) |
|
284 self._draw_turtle() |
|
285 |
|
286 def fill(self, flag): |
|
287 """ Call fill(1) before drawing the shape you |
|
288 want to fill, and fill(0) when done. |
|
289 |
|
290 Example: |
|
291 >>> turtle.fill(1) |
|
292 >>> turtle.forward(100) |
|
293 >>> turtle.left(90) |
|
294 >>> turtle.forward(100) |
|
295 >>> turtle.left(90) |
|
296 >>> turtle.forward(100) |
|
297 >>> turtle.left(90) |
|
298 >>> turtle.forward(100) |
|
299 >>> turtle.fill(0) |
|
300 """ |
|
301 if self._filling: |
|
302 path = tuple(self._path) |
|
303 smooth = self._filling < 0 |
|
304 if len(path) > 2: |
|
305 item = self._canvas._create('polygon', path, |
|
306 {'fill': self._color, |
|
307 'smooth': smooth}) |
|
308 self._items.append(item) |
|
309 self._path = [] |
|
310 self._filling = flag |
|
311 if flag: |
|
312 self._path.append(self._position) |
|
313 |
|
314 def begin_fill(self): |
|
315 """ Called just before drawing a shape to be filled. |
|
316 Must eventually be followed by a corresponding end_fill() call. |
|
317 Otherwise it will be ignored. |
|
318 |
|
319 Example: |
|
320 >>> turtle.begin_fill() |
|
321 >>> turtle.forward(100) |
|
322 >>> turtle.left(90) |
|
323 >>> turtle.forward(100) |
|
324 >>> turtle.left(90) |
|
325 >>> turtle.forward(100) |
|
326 >>> turtle.left(90) |
|
327 >>> turtle.forward(100) |
|
328 >>> turtle.end_fill() |
|
329 """ |
|
330 self._path = [self._position] |
|
331 self._filling = 1 |
|
332 |
|
333 def end_fill(self): |
|
334 """ Called after drawing a shape to be filled. |
|
335 |
|
336 Example: |
|
337 >>> turtle.begin_fill() |
|
338 >>> turtle.forward(100) |
|
339 >>> turtle.left(90) |
|
340 >>> turtle.forward(100) |
|
341 >>> turtle.left(90) |
|
342 >>> turtle.forward(100) |
|
343 >>> turtle.left(90) |
|
344 >>> turtle.forward(100) |
|
345 >>> turtle.end_fill() |
|
346 """ |
|
347 self.fill(0) |
|
348 |
|
349 def circle(self, radius, extent = None): |
|
350 """ Draw a circle with given radius. |
|
351 The center is radius units left of the turtle; extent |
|
352 determines which part of the circle is drawn. If not given, |
|
353 the entire circle is drawn. |
|
354 |
|
355 If extent is not a full circle, one endpoint of the arc is the |
|
356 current pen position. The arc is drawn in a counter clockwise |
|
357 direction if radius is positive, otherwise in a clockwise |
|
358 direction. In the process, the direction of the turtle is |
|
359 changed by the amount of the extent. |
|
360 |
|
361 >>> turtle.circle(50) |
|
362 >>> turtle.circle(120, 180) # half a circle |
|
363 """ |
|
364 if extent is None: |
|
365 extent = self._fullcircle |
|
366 frac = abs(extent)/self._fullcircle |
|
367 steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac) |
|
368 w = 1.0 * extent / steps |
|
369 w2 = 0.5 * w |
|
370 l = 2.0 * radius * sin(w2*self._invradian) |
|
371 if radius < 0: |
|
372 l, w, w2 = -l, -w, -w2 |
|
373 self.left(w2) |
|
374 for i in range(steps): |
|
375 self.forward(l) |
|
376 self.left(w) |
|
377 self.right(w2) |
|
378 |
|
379 def heading(self): |
|
380 """ Return the turtle's current heading. |
|
381 |
|
382 Example: |
|
383 >>> turtle.heading() |
|
384 67.0 |
|
385 """ |
|
386 return self._angle |
|
387 |
|
388 def setheading(self, angle): |
|
389 """ Set the turtle facing the given angle. |
|
390 |
|
391 Here are some common directions in degrees: |
|
392 |
|
393 0 - east |
|
394 90 - north |
|
395 180 - west |
|
396 270 - south |
|
397 |
|
398 Example: |
|
399 >>> turtle.setheading(90) |
|
400 >>> turtle.heading() |
|
401 90 |
|
402 >>> turtle.setheading(128) |
|
403 >>> turtle.heading() |
|
404 128 |
|
405 """ |
|
406 self._angle = angle |
|
407 self._draw_turtle() |
|
408 |
|
409 def window_width(self): |
|
410 """ Returns the width of the turtle window. |
|
411 |
|
412 Example: |
|
413 >>> turtle.window_width() |
|
414 640 |
|
415 """ |
|
416 width = self._canvas.winfo_width() |
|
417 if width <= 1: # the window isn't managed by a geometry manager |
|
418 width = self._canvas['width'] |
|
419 return width |
|
420 |
|
421 def window_height(self): |
|
422 """ Return the height of the turtle window. |
|
423 |
|
424 Example: |
|
425 >>> turtle.window_height() |
|
426 768 |
|
427 """ |
|
428 height = self._canvas.winfo_height() |
|
429 if height <= 1: # the window isn't managed by a geometry manager |
|
430 height = self._canvas['height'] |
|
431 return height |
|
432 |
|
433 def position(self): |
|
434 """ Return the current (x, y) location of the turtle. |
|
435 |
|
436 Example: |
|
437 >>> turtle.position() |
|
438 [0.0, 240.0] |
|
439 """ |
|
440 x0, y0 = self._origin |
|
441 x1, y1 = self._position |
|
442 return [x1-x0, -y1+y0] |
|
443 |
|
444 def setx(self, xpos): |
|
445 """ Set the turtle's x coordinate to be xpos. |
|
446 |
|
447 Example: |
|
448 >>> turtle.position() |
|
449 [10.0, 240.0] |
|
450 >>> turtle.setx(10) |
|
451 >>> turtle.position() |
|
452 [10.0, 240.0] |
|
453 """ |
|
454 x0, y0 = self._origin |
|
455 x1, y1 = self._position |
|
456 self._goto(x0+xpos, y1) |
|
457 |
|
458 def sety(self, ypos): |
|
459 """ Set the turtle's y coordinate to be ypos. |
|
460 |
|
461 Example: |
|
462 >>> turtle.position() |
|
463 [0.0, 0.0] |
|
464 >>> turtle.sety(-22) |
|
465 >>> turtle.position() |
|
466 [0.0, -22.0] |
|
467 """ |
|
468 x0, y0 = self._origin |
|
469 x1, y1 = self._position |
|
470 self._goto(x1, y0-ypos) |
|
471 |
|
472 def towards(self, *args): |
|
473 """Returs the angle, which corresponds to the line |
|
474 from turtle-position to point (x,y). |
|
475 |
|
476 Argument can be two coordinates or one pair of coordinates |
|
477 or a RawPen/Pen instance. |
|
478 |
|
479 Example: |
|
480 >>> turtle.position() |
|
481 [10.0, 10.0] |
|
482 >>> turtle.towards(0,0) |
|
483 225.0 |
|
484 """ |
|
485 if len(args) == 2: |
|
486 x, y = args |
|
487 else: |
|
488 arg = args[0] |
|
489 if isinstance(arg, RawPen): |
|
490 x, y = arg.position() |
|
491 else: |
|
492 x, y = arg |
|
493 x0, y0 = self.position() |
|
494 dx = x - x0 |
|
495 dy = y - y0 |
|
496 return (atan2(dy,dx) / self._invradian) % self._fullcircle |
|
497 |
|
498 def goto(self, *args): |
|
499 """ Go to the given point. |
|
500 |
|
501 If the pen is down, then a line will be drawn. The turtle's |
|
502 orientation does not change. |
|
503 |
|
504 Two input formats are accepted: |
|
505 |
|
506 goto(x, y) |
|
507 go to point (x, y) |
|
508 |
|
509 goto((x, y)) |
|
510 go to point (x, y) |
|
511 |
|
512 Example: |
|
513 >>> turtle.position() |
|
514 [0.0, 0.0] |
|
515 >>> turtle.goto(50, -45) |
|
516 >>> turtle.position() |
|
517 [50.0, -45.0] |
|
518 """ |
|
519 if len(args) == 1: |
|
520 try: |
|
521 x, y = args[0] |
|
522 except: |
|
523 raise Error, "bad point argument: %r" % (args[0],) |
|
524 else: |
|
525 try: |
|
526 x, y = args |
|
527 except: |
|
528 raise Error, "bad coordinates: %r" % (args[0],) |
|
529 x0, y0 = self._origin |
|
530 self._goto(x0+x, y0-y) |
|
531 |
|
532 def _goto(self, x1, y1): |
|
533 x0, y0 = self._position |
|
534 self._position = map(float, (x1, y1)) |
|
535 if self._filling: |
|
536 self._path.append(self._position) |
|
537 if self._drawing: |
|
538 if self._tracing: |
|
539 dx = float(x1 - x0) |
|
540 dy = float(y1 - y0) |
|
541 distance = hypot(dx, dy) |
|
542 nhops = int(distance) |
|
543 item = self._canvas.create_line(x0, y0, x0, y0, |
|
544 width=self._width, |
|
545 capstyle="round", |
|
546 fill=self._color) |
|
547 try: |
|
548 for i in range(1, 1+nhops): |
|
549 x, y = x0 + dx*i/nhops, y0 + dy*i/nhops |
|
550 self._canvas.coords(item, x0, y0, x, y) |
|
551 self._draw_turtle((x,y)) |
|
552 self._canvas.update() |
|
553 self._canvas.after(self._delay) |
|
554 # in case nhops==0 |
|
555 self._canvas.coords(item, x0, y0, x1, y1) |
|
556 self._canvas.itemconfigure(item, arrow="none") |
|
557 except Tkinter.TclError: |
|
558 # Probably the window was closed! |
|
559 return |
|
560 else: |
|
561 item = self._canvas.create_line(x0, y0, x1, y1, |
|
562 width=self._width, |
|
563 capstyle="round", |
|
564 fill=self._color) |
|
565 self._items.append(item) |
|
566 self._draw_turtle() |
|
567 |
|
568 def speed(self, speed): |
|
569 """ Set the turtle's speed. |
|
570 |
|
571 speed must one of these five strings: |
|
572 |
|
573 'fastest' is a 0 ms delay |
|
574 'fast' is a 5 ms delay |
|
575 'normal' is a 10 ms delay |
|
576 'slow' is a 15 ms delay |
|
577 'slowest' is a 20 ms delay |
|
578 |
|
579 Example: |
|
580 >>> turtle.speed('slow') |
|
581 """ |
|
582 try: |
|
583 speed = speed.strip().lower() |
|
584 self._delay = speeds.index(speed) * 5 |
|
585 except: |
|
586 raise ValueError("%r is not a valid speed. speed must be " |
|
587 "one of %s" % (speed, speeds)) |
|
588 |
|
589 |
|
590 def delay(self, delay): |
|
591 """ Set the drawing delay in milliseconds. |
|
592 |
|
593 This is intended to allow finer control of the drawing speed |
|
594 than the speed() method |
|
595 |
|
596 Example: |
|
597 >>> turtle.delay(15) |
|
598 """ |
|
599 if int(delay) < 0: |
|
600 raise ValueError("delay must be greater than or equal to 0") |
|
601 self._delay = int(delay) |
|
602 |
|
603 def _draw_turtle(self, position=[]): |
|
604 if not self._tracing: |
|
605 self._canvas.update() |
|
606 return |
|
607 if position == []: |
|
608 position = self._position |
|
609 x,y = position |
|
610 distance = 8 |
|
611 dx = distance * cos(self._angle*self._invradian) |
|
612 dy = distance * sin(self._angle*self._invradian) |
|
613 self._delete_turtle() |
|
614 self._arrow = self._canvas.create_line(x-dx,y+dy,x,y, |
|
615 width=self._width, |
|
616 arrow="last", |
|
617 capstyle="round", |
|
618 fill=self._color) |
|
619 self._canvas.update() |
|
620 |
|
621 def _delete_turtle(self): |
|
622 if self._arrow != 0: |
|
623 self._canvas.delete(self._arrow) |
|
624 self._arrow = 0 |
|
625 |
|
626 |
|
627 _root = None |
|
628 _canvas = None |
|
629 _pen = None |
|
630 _width = 0.50 # 50% of window width |
|
631 _height = 0.75 # 75% of window height |
|
632 _startx = None |
|
633 _starty = None |
|
634 _title = "Turtle Graphics" # default title |
|
635 |
|
636 class Pen(RawPen): |
|
637 |
|
638 def __init__(self): |
|
639 global _root, _canvas |
|
640 if _root is None: |
|
641 _root = Tkinter.Tk() |
|
642 _root.wm_protocol("WM_DELETE_WINDOW", self._destroy) |
|
643 _root.title(_title) |
|
644 |
|
645 if _canvas is None: |
|
646 # XXX Should have scroll bars |
|
647 _canvas = Tkinter.Canvas(_root, background="white") |
|
648 _canvas.pack(expand=1, fill="both") |
|
649 |
|
650 setup(width=_width, height= _height, startx=_startx, starty=_starty) |
|
651 |
|
652 RawPen.__init__(self, _canvas) |
|
653 |
|
654 def _destroy(self): |
|
655 global _root, _canvas, _pen |
|
656 root = self._canvas._root() |
|
657 if root is _root: |
|
658 _pen = None |
|
659 _root = None |
|
660 _canvas = None |
|
661 root.destroy() |
|
662 |
|
663 def _getpen(): |
|
664 global _pen |
|
665 if not _pen: |
|
666 _pen = Pen() |
|
667 return _pen |
|
668 |
|
669 class Turtle(Pen): |
|
670 pass |
|
671 |
|
672 """For documentation of the following functions see |
|
673 the RawPen methods with the same names |
|
674 """ |
|
675 |
|
676 def degrees(): _getpen().degrees() |
|
677 def radians(): _getpen().radians() |
|
678 def reset(): _getpen().reset() |
|
679 def clear(): _getpen().clear() |
|
680 def tracer(flag): _getpen().tracer(flag) |
|
681 def forward(distance): _getpen().forward(distance) |
|
682 def backward(distance): _getpen().backward(distance) |
|
683 def left(angle): _getpen().left(angle) |
|
684 def right(angle): _getpen().right(angle) |
|
685 def up(): _getpen().up() |
|
686 def down(): _getpen().down() |
|
687 def width(width): _getpen().width(width) |
|
688 def color(*args): _getpen().color(*args) |
|
689 def write(arg, move=0): _getpen().write(arg, move) |
|
690 def fill(flag): _getpen().fill(flag) |
|
691 def begin_fill(): _getpen().begin_fill() |
|
692 def end_fill(): _getpen().end_fill() |
|
693 def circle(radius, extent=None): _getpen().circle(radius, extent) |
|
694 def goto(*args): _getpen().goto(*args) |
|
695 def heading(): return _getpen().heading() |
|
696 def setheading(angle): _getpen().setheading(angle) |
|
697 def position(): return _getpen().position() |
|
698 def window_width(): return _getpen().window_width() |
|
699 def window_height(): return _getpen().window_height() |
|
700 def setx(xpos): _getpen().setx(xpos) |
|
701 def sety(ypos): _getpen().sety(ypos) |
|
702 def towards(*args): return _getpen().towards(*args) |
|
703 |
|
704 def done(): _root.mainloop() |
|
705 def delay(delay): return _getpen().delay(delay) |
|
706 def speed(speed): return _getpen().speed(speed) |
|
707 |
|
708 for methodname in dir(RawPen): |
|
709 """ copies RawPen docstrings to module functions of same name """ |
|
710 if not methodname.startswith("_"): |
|
711 eval(methodname).__doc__ = RawPen.__dict__[methodname].__doc__ |
|
712 |
|
713 |
|
714 def setup(**geometry): |
|
715 """ Sets the size and position of the main window. |
|
716 |
|
717 Keywords are width, height, startx and starty: |
|
718 |
|
719 width: either a size in pixels or a fraction of the screen. |
|
720 Default is 50% of screen. |
|
721 height: either the height in pixels or a fraction of the screen. |
|
722 Default is 75% of screen. |
|
723 |
|
724 Setting either width or height to None before drawing will force |
|
725 use of default geometry as in older versions of turtle.py |
|
726 |
|
727 startx: starting position in pixels from the left edge of the screen. |
|
728 Default is to center window. Setting startx to None is the default |
|
729 and centers window horizontally on screen. |
|
730 |
|
731 starty: starting position in pixels from the top edge of the screen. |
|
732 Default is to center window. Setting starty to None is the default |
|
733 and centers window vertically on screen. |
|
734 |
|
735 Examples: |
|
736 >>> setup (width=200, height=200, startx=0, starty=0) |
|
737 |
|
738 sets window to 200x200 pixels, in upper left of screen |
|
739 |
|
740 >>> setup(width=.75, height=0.5, startx=None, starty=None) |
|
741 |
|
742 sets window to 75% of screen by 50% of screen and centers |
|
743 |
|
744 >>> setup(width=None) |
|
745 |
|
746 forces use of default geometry as in older versions of turtle.py |
|
747 """ |
|
748 |
|
749 global _width, _height, _startx, _starty |
|
750 |
|
751 width = geometry.get('width',_width) |
|
752 if width >= 0 or width == None: |
|
753 _width = width |
|
754 else: |
|
755 raise ValueError, "width can not be less than 0" |
|
756 |
|
757 height = geometry.get('height',_height) |
|
758 if height >= 0 or height == None: |
|
759 _height = height |
|
760 else: |
|
761 raise ValueError, "height can not be less than 0" |
|
762 |
|
763 startx = geometry.get('startx', _startx) |
|
764 if startx >= 0 or startx == None: |
|
765 _startx = _startx |
|
766 else: |
|
767 raise ValueError, "startx can not be less than 0" |
|
768 |
|
769 starty = geometry.get('starty', _starty) |
|
770 if starty >= 0 or starty == None: |
|
771 _starty = starty |
|
772 else: |
|
773 raise ValueError, "startx can not be less than 0" |
|
774 |
|
775 |
|
776 if _root and _width and _height: |
|
777 if 0 < _width <= 1: |
|
778 _width = _root.winfo_screenwidth() * +width |
|
779 if 0 < _height <= 1: |
|
780 _height = _root.winfo_screenheight() * _height |
|
781 |
|
782 # center window on screen |
|
783 if _startx is None: |
|
784 _startx = (_root.winfo_screenwidth() - _width) / 2 |
|
785 |
|
786 if _starty is None: |
|
787 _starty = (_root.winfo_screenheight() - _height) / 2 |
|
788 |
|
789 _root.geometry("%dx%d+%d+%d" % (_width, _height, _startx, _starty)) |
|
790 |
|
791 def title(title): |
|
792 """Set the window title. |
|
793 |
|
794 By default this is set to 'Turtle Graphics' |
|
795 |
|
796 Example: |
|
797 >>> title("My Window") |
|
798 """ |
|
799 |
|
800 global _title |
|
801 _title = title |
|
802 |
|
803 def demo(): |
|
804 reset() |
|
805 tracer(1) |
|
806 up() |
|
807 backward(100) |
|
808 down() |
|
809 # draw 3 squares; the last filled |
|
810 width(3) |
|
811 for i in range(3): |
|
812 if i == 2: |
|
813 fill(1) |
|
814 for j in range(4): |
|
815 forward(20) |
|
816 left(90) |
|
817 if i == 2: |
|
818 color("maroon") |
|
819 fill(0) |
|
820 up() |
|
821 forward(30) |
|
822 down() |
|
823 width(1) |
|
824 color("black") |
|
825 # move out of the way |
|
826 tracer(0) |
|
827 up() |
|
828 right(90) |
|
829 forward(100) |
|
830 right(90) |
|
831 forward(100) |
|
832 right(180) |
|
833 down() |
|
834 # some text |
|
835 write("startstart", 1) |
|
836 write("start", 1) |
|
837 color("red") |
|
838 # staircase |
|
839 for i in range(5): |
|
840 forward(20) |
|
841 left(90) |
|
842 forward(20) |
|
843 right(90) |
|
844 # filled staircase |
|
845 fill(1) |
|
846 for i in range(5): |
|
847 forward(20) |
|
848 left(90) |
|
849 forward(20) |
|
850 right(90) |
|
851 fill(0) |
|
852 tracer(1) |
|
853 # more text |
|
854 write("end") |
|
855 |
|
856 def demo2(): |
|
857 # exercises some new and improved features |
|
858 speed('fast') |
|
859 width(3) |
|
860 |
|
861 # draw a segmented half-circle |
|
862 setheading(towards(0,0)) |
|
863 x,y = position() |
|
864 r = (x**2+y**2)**.5/2.0 |
|
865 right(90) |
|
866 pendown = True |
|
867 for i in range(18): |
|
868 if pendown: |
|
869 up() |
|
870 pendown = False |
|
871 else: |
|
872 down() |
|
873 pendown = True |
|
874 circle(r,10) |
|
875 sleep(2) |
|
876 |
|
877 reset() |
|
878 left(90) |
|
879 |
|
880 # draw a series of triangles |
|
881 l = 10 |
|
882 color("green") |
|
883 width(3) |
|
884 left(180) |
|
885 sp = 5 |
|
886 for i in range(-2,16): |
|
887 if i > 0: |
|
888 color(1.0-0.05*i,0,0.05*i) |
|
889 fill(1) |
|
890 color("green") |
|
891 for j in range(3): |
|
892 forward(l) |
|
893 left(120) |
|
894 l += 10 |
|
895 left(15) |
|
896 if sp > 0: |
|
897 sp = sp-1 |
|
898 speed(speeds[sp]) |
|
899 color(0.25,0,0.75) |
|
900 fill(0) |
|
901 |
|
902 # draw and fill a concave shape |
|
903 left(120) |
|
904 up() |
|
905 forward(70) |
|
906 right(30) |
|
907 down() |
|
908 color("red") |
|
909 speed("fastest") |
|
910 fill(1) |
|
911 for i in range(4): |
|
912 circle(50,90) |
|
913 right(90) |
|
914 forward(30) |
|
915 right(90) |
|
916 color("yellow") |
|
917 fill(0) |
|
918 left(90) |
|
919 up() |
|
920 forward(30) |
|
921 down(); |
|
922 |
|
923 color("red") |
|
924 |
|
925 # create a second turtle and make the original pursue and catch it |
|
926 turtle=Turtle() |
|
927 turtle.reset() |
|
928 turtle.left(90) |
|
929 turtle.speed('normal') |
|
930 turtle.up() |
|
931 turtle.goto(280,40) |
|
932 turtle.left(24) |
|
933 turtle.down() |
|
934 turtle.speed('fast') |
|
935 turtle.color("blue") |
|
936 turtle.width(2) |
|
937 speed('fastest') |
|
938 |
|
939 # turn default turtle towards new turtle object |
|
940 setheading(towards(turtle)) |
|
941 while ( abs(position()[0]-turtle.position()[0])>4 or |
|
942 abs(position()[1]-turtle.position()[1])>4): |
|
943 turtle.forward(3.5) |
|
944 turtle.left(0.6) |
|
945 # turn default turtle towards new turtle object |
|
946 setheading(towards(turtle)) |
|
947 forward(4) |
|
948 write("CAUGHT! ", move=True) |
|
949 |
|
950 |
|
951 |
|
952 if __name__ == '__main__': |
|
953 demo() |
|
954 sleep(3) |
|
955 demo2() |
|
956 done() |