jpayne@68
|
1 #!/usr/bin/env python3
|
jpayne@68
|
2 """ turtle-example-suite:
|
jpayne@68
|
3
|
jpayne@68
|
4 tdemo_fractalCurves.py
|
jpayne@68
|
5
|
jpayne@68
|
6 This program draws two fractal-curve-designs:
|
jpayne@68
|
7 (1) A hilbert curve (in a box)
|
jpayne@68
|
8 (2) A combination of Koch-curves.
|
jpayne@68
|
9
|
jpayne@68
|
10 The CurvesTurtle class and the fractal-curve-
|
jpayne@68
|
11 methods are taken from the PythonCard example
|
jpayne@68
|
12 scripts for turtle-graphics.
|
jpayne@68
|
13 """
|
jpayne@68
|
14 from turtle import *
|
jpayne@68
|
15 from time import sleep, perf_counter as clock
|
jpayne@68
|
16
|
jpayne@68
|
17 class CurvesTurtle(Pen):
|
jpayne@68
|
18 # example derived from
|
jpayne@68
|
19 # Turtle Geometry: The Computer as a Medium for Exploring Mathematics
|
jpayne@68
|
20 # by Harold Abelson and Andrea diSessa
|
jpayne@68
|
21 # p. 96-98
|
jpayne@68
|
22 def hilbert(self, size, level, parity):
|
jpayne@68
|
23 if level == 0:
|
jpayne@68
|
24 return
|
jpayne@68
|
25 # rotate and draw first subcurve with opposite parity to big curve
|
jpayne@68
|
26 self.left(parity * 90)
|
jpayne@68
|
27 self.hilbert(size, level - 1, -parity)
|
jpayne@68
|
28 # interface to and draw second subcurve with same parity as big curve
|
jpayne@68
|
29 self.forward(size)
|
jpayne@68
|
30 self.right(parity * 90)
|
jpayne@68
|
31 self.hilbert(size, level - 1, parity)
|
jpayne@68
|
32 # third subcurve
|
jpayne@68
|
33 self.forward(size)
|
jpayne@68
|
34 self.hilbert(size, level - 1, parity)
|
jpayne@68
|
35 # fourth subcurve
|
jpayne@68
|
36 self.right(parity * 90)
|
jpayne@68
|
37 self.forward(size)
|
jpayne@68
|
38 self.hilbert(size, level - 1, -parity)
|
jpayne@68
|
39 # a final turn is needed to make the turtle
|
jpayne@68
|
40 # end up facing outward from the large square
|
jpayne@68
|
41 self.left(parity * 90)
|
jpayne@68
|
42
|
jpayne@68
|
43 # Visual Modeling with Logo: A Structural Approach to Seeing
|
jpayne@68
|
44 # by James Clayson
|
jpayne@68
|
45 # Koch curve, after Helge von Koch who introduced this geometric figure in 1904
|
jpayne@68
|
46 # p. 146
|
jpayne@68
|
47 def fractalgon(self, n, rad, lev, dir):
|
jpayne@68
|
48 import math
|
jpayne@68
|
49
|
jpayne@68
|
50 # if dir = 1 turn outward
|
jpayne@68
|
51 # if dir = -1 turn inward
|
jpayne@68
|
52 edge = 2 * rad * math.sin(math.pi / n)
|
jpayne@68
|
53 self.pu()
|
jpayne@68
|
54 self.fd(rad)
|
jpayne@68
|
55 self.pd()
|
jpayne@68
|
56 self.rt(180 - (90 * (n - 2) / n))
|
jpayne@68
|
57 for i in range(n):
|
jpayne@68
|
58 self.fractal(edge, lev, dir)
|
jpayne@68
|
59 self.rt(360 / n)
|
jpayne@68
|
60 self.lt(180 - (90 * (n - 2) / n))
|
jpayne@68
|
61 self.pu()
|
jpayne@68
|
62 self.bk(rad)
|
jpayne@68
|
63 self.pd()
|
jpayne@68
|
64
|
jpayne@68
|
65 # p. 146
|
jpayne@68
|
66 def fractal(self, dist, depth, dir):
|
jpayne@68
|
67 if depth < 1:
|
jpayne@68
|
68 self.fd(dist)
|
jpayne@68
|
69 return
|
jpayne@68
|
70 self.fractal(dist / 3, depth - 1, dir)
|
jpayne@68
|
71 self.lt(60 * dir)
|
jpayne@68
|
72 self.fractal(dist / 3, depth - 1, dir)
|
jpayne@68
|
73 self.rt(120 * dir)
|
jpayne@68
|
74 self.fractal(dist / 3, depth - 1, dir)
|
jpayne@68
|
75 self.lt(60 * dir)
|
jpayne@68
|
76 self.fractal(dist / 3, depth - 1, dir)
|
jpayne@68
|
77
|
jpayne@68
|
78 def main():
|
jpayne@68
|
79 ft = CurvesTurtle()
|
jpayne@68
|
80
|
jpayne@68
|
81 ft.reset()
|
jpayne@68
|
82 ft.speed(0)
|
jpayne@68
|
83 ft.ht()
|
jpayne@68
|
84 ft.getscreen().tracer(1,0)
|
jpayne@68
|
85 ft.pu()
|
jpayne@68
|
86
|
jpayne@68
|
87 size = 6
|
jpayne@68
|
88 ft.setpos(-33*size, -32*size)
|
jpayne@68
|
89 ft.pd()
|
jpayne@68
|
90
|
jpayne@68
|
91 ta=clock()
|
jpayne@68
|
92 ft.fillcolor("red")
|
jpayne@68
|
93 ft.begin_fill()
|
jpayne@68
|
94 ft.fd(size)
|
jpayne@68
|
95
|
jpayne@68
|
96 ft.hilbert(size, 6, 1)
|
jpayne@68
|
97
|
jpayne@68
|
98 # frame
|
jpayne@68
|
99 ft.fd(size)
|
jpayne@68
|
100 for i in range(3):
|
jpayne@68
|
101 ft.lt(90)
|
jpayne@68
|
102 ft.fd(size*(64+i%2))
|
jpayne@68
|
103 ft.pu()
|
jpayne@68
|
104 for i in range(2):
|
jpayne@68
|
105 ft.fd(size)
|
jpayne@68
|
106 ft.rt(90)
|
jpayne@68
|
107 ft.pd()
|
jpayne@68
|
108 for i in range(4):
|
jpayne@68
|
109 ft.fd(size*(66+i%2))
|
jpayne@68
|
110 ft.rt(90)
|
jpayne@68
|
111 ft.end_fill()
|
jpayne@68
|
112 tb=clock()
|
jpayne@68
|
113 res = "Hilbert: %.2fsec. " % (tb-ta)
|
jpayne@68
|
114
|
jpayne@68
|
115 sleep(3)
|
jpayne@68
|
116
|
jpayne@68
|
117 ft.reset()
|
jpayne@68
|
118 ft.speed(0)
|
jpayne@68
|
119 ft.ht()
|
jpayne@68
|
120 ft.getscreen().tracer(1,0)
|
jpayne@68
|
121
|
jpayne@68
|
122 ta=clock()
|
jpayne@68
|
123 ft.color("black", "blue")
|
jpayne@68
|
124 ft.begin_fill()
|
jpayne@68
|
125 ft.fractalgon(3, 250, 4, 1)
|
jpayne@68
|
126 ft.end_fill()
|
jpayne@68
|
127 ft.begin_fill()
|
jpayne@68
|
128 ft.color("red")
|
jpayne@68
|
129 ft.fractalgon(3, 200, 4, -1)
|
jpayne@68
|
130 ft.end_fill()
|
jpayne@68
|
131 tb=clock()
|
jpayne@68
|
132 res += "Koch: %.2fsec." % (tb-ta)
|
jpayne@68
|
133 return res
|
jpayne@68
|
134
|
jpayne@68
|
135 if __name__ == '__main__':
|
jpayne@68
|
136 msg = main()
|
jpayne@68
|
137 print(msg)
|
jpayne@68
|
138 mainloop()
|