|
| 1 | +import turtle |
| 2 | +import math |
| 3 | +import random |
| 4 | + |
| 5 | +screen = turtle.Screen() |
| 6 | +screen.setup(1000,1000) |
| 7 | +screen.title("Random Cloud - PythonTurtle.Academy") |
| 8 | + |
| 9 | +turtle.speed(0) |
| 10 | +turtle.hideturtle() |
| 11 | +turtle.up() |
| 12 | +turtle.bgcolor('dodger blue') |
| 13 | +turtle.pencolor('white') |
| 14 | +turtle.pensize(2) |
| 15 | + |
| 16 | +n = 500 # number of points on each ellipse |
| 17 | +# X,Y is the center of ellipse, a is radius on x-axis, b is radius on y-axis |
| 18 | +# ts is the starting angle of the ellipse, te is the ending angle of the ellipse |
| 19 | +# P is the list of coordinates of the points on the ellipse |
| 20 | +def ellipse(X,Y,a,b,ts,te,P): |
| 21 | + t = ts |
| 22 | + for i in range(n): |
| 23 | + x = a*math.cos(t) |
| 24 | + y = b*math.sin(t) |
| 25 | + P.append((x+X,y+Y)) |
| 26 | + t += (te-ts)/(n-1) |
| 27 | + |
| 28 | +# computes Euclidean distance between p1 and p2 |
| 29 | +def dist(p1,p2): |
| 30 | + return ((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)**0.5 |
| 31 | + |
| 32 | +# draws an arc from p1 to p2 with extent value ext |
| 33 | +def draw_arc(p1,p2,ext): |
| 34 | + turtle.up() |
| 35 | + turtle.goto(p1) |
| 36 | + turtle.seth(turtle.towards(p2)) |
| 37 | + a = turtle.heading() |
| 38 | + b = 360-ext |
| 39 | + c = (180-b)/2 |
| 40 | + d = a-c |
| 41 | + e = d-90 |
| 42 | + r = dist(p1,p2)/2/math.sin(math.radians(b/2)) # r is the radius of the arc |
| 43 | + turtle.seth(e) # e is initial heading of the circle |
| 44 | + turtle.down() |
| 45 | + turtle.circle(r,ext,100) |
| 46 | + return (turtle.xcor(),turtle.ycor()) # returns the landing position of the circle |
| 47 | + # this position should be extremely close to p2 but may not be exactly the same |
| 48 | + # return this for continuous drawing to the next point |
| 49 | + |
| 50 | + |
| 51 | +def cloud(P): |
| 52 | + step = n//10 # draw about 10 arcs on top and bottom part of cloud |
| 53 | + a = 0 # a is index of first point |
| 54 | + b = a + random.randint(step//2,step*2) # b is index of second point |
| 55 | + p1 = P[a] # p1 is the position of the first point |
| 56 | + p2 = P[b] # p2 is the position of the second point |
| 57 | + turtle.fillcolor('white') |
| 58 | + turtle.begin_fill() |
| 59 | + p3 = draw_arc(p1,p2,random.uniform(70,180)) # draws the arc with random extention |
| 60 | + while b < len(P)-1: |
| 61 | + p1 = p3 # start from the end of the last arc |
| 62 | + if b < len(P)/2: # first half is top, more ragged |
| 63 | + ext = random.uniform(70,180) |
| 64 | + b += random.randint(step//2,step*2) |
| 65 | + else: # second half is bottom, more smooth |
| 66 | + ext = random.uniform(30,70) |
| 67 | + b += random.randint(step,step*2) |
| 68 | + b = min(b,len(P)-1) # make sure to not skip past the last point |
| 69 | + p2 = P[b] # second point |
| 70 | + p3 = draw_arc(p1,p2,ext) # draws an arc and return the end position |
| 71 | + turtle.end_fill() |
| 72 | + |
| 73 | +P = [] # starting from empty list |
| 74 | +ellipse(0,0,300,200,0,math.pi,P) # taller top half |
| 75 | +ellipse(0,0,300,50,math.pi,math.pi*2,P) # shorter bottom half |
| 76 | +cloud(P) |
0 commit comments