From ac3ece85713b1c2b998801a51dca173cbc4216f2 Mon Sep 17 00:00:00 2001 From: Dinko Galetic Date: Thu, 03 Jun 2010 07:19:18 +0000 Subject: Added a Python script which draws the Koch snowflake. --- (limited to 'data') diff --git a/data/GSOC examples/Koch snowflake b/data/GSOC examples/Koch snowflake new file mode 100644 index 0000000..2fb218e --- /dev/null +++ b/data/GSOC examples/Koch snowflake @@ -0,0 +1,208 @@ +# This example draws a shape called the Koch snowflake. + +import pippy, pygame, sys +from pygame.locals import * +from random import * +import math + +# always need to init first thing +pygame.init() + +# XO screen is 1200x900 +size = width, height = 1200, 900 + +# create the window and keep track of the surface +# for drawing into +screen = pygame.display.set_mode(size) + +# turn off the cursor +pygame.mouse.set_visible(False) + + +# Set some variables. +# Snowflakes are white! +color = (255,255,255) + +# the center point of the screen +# We need it because we'll place out triangle around it. +center = width / 2, height / 2 + +# Side of an equilateral triangle (the one we start with). +# Here it is defined relative to the resolution of the screen. +# Practice: We could play with other values, absolute (like a = 100) or +# relative (a = height / 2, a = width / 3, etc). What looks best for you? +a = height/1.4 + +# Height of that triangle. +# Just a simple geometry formula, nothing Python-special about it. +h = int(a * math.sqrt(3) / 2) + +# These will be the vertices for the starting triangle. +# The triangle vertices are named like this: +# +# C +# / \ +# A _ B +# +A = center[0]- a/2, center[1] + h/3 +B = A[0] + a, A[1] +# To find the third point, we need slightly more advanced math. +# If you with to understand it, you could try finding some material about trigonometry. +# We use the coordinates of vertice A to calculate where point C will be. +C = A[0] + math.cos(math.pi/3) * a, A[1] - math.sin(math.pi/3) * a + +# This class will allow us to store data about a line. +class Line(object): + def __init__(self, a = A, b = B): + # This is how a line object will remember its points and length. + self.A = a + self.B = b + self.points = [self.A, self.B] + + # We use the Pythagorean theorem to calculate the length of a line + # from the coordinates of its points. + self.length = math.sqrt( (a[0]-b[0])**2 + (a[1]-b[1])**2 ) + + # Projection of the line on the x axis. + # We use it to figure out the angle which the line closes with the x axis. + projection_length = b[0] - a[0] + + # If the line is descending, the angle is negative. Trigonometry, again. + if b[1] > a[1]: + self.angle = -math.acos(projection_length / self.length) + else: + self.angle = math.acos(projection_length / self.length) + + # To draw new shapes, an old line must be split into its thirds. + def split(self): + third = self.length / 3.0 + self.D = self.A[0] + math.cos(self.angle) * third, \ + self.A[1] - math.sin(self.angle) * third + self.E = self.A[0] + math.cos(self.angle) * 2*third, \ + self.A[1] - math.sin(self.angle) * 2*third + self.points.append(self.D) + self.points.append(self.E) + +# Give a line (from which we'll need the coordinates of its starting point) and +# an angle, calculate the position of a new point - the vertex of out snowflake. +# The length of its sides should be 1/3 of the length of the line from which +# it is made. +def calculate_new_point(line, angle): + p = line.D[0] + math.cos(angle + line.angle) * line.length / 3, \ + line.D[1] - math.sin(angle + line.angle) * line.length / 3 + return p + + +# The following function from a single line, like this: +# +# A___B +# +# creates four lines, like this: +# +# F +# A_D/ \E_B +# +def transform_line(line): + line.split() + C = calculate_new_point(line, math.pi/3) + line1 = Line(line.A, line.D) + line2 = Line(line.D, C) + line3 = Line(C, line.E) + line4 = Line(line.E, line. B) + lines = [line1, line2, line3, line4] + return lines + +# For each line in starting_lines, call transform_line(). +# Repeat "depth" times for each line created this way. +def produce_lines(starting_lines, depth): + all_lines = starting_lines + for i in range(depth): + new_lines = [] + for line in all_lines: + new_lines += transform_line(line) + # clearn the old lines first + all_lines = [] + all_lines = new_lines + return all_lines + +# Write the lines on screen. +def draw_lines(lines): + for line in lines: + pygame.draw.line(screen, color, line.A, line.B) + + +# The color we'll use for the screen background (black). +bgcolor = (0,0,0) + + +# Lines for the initial triangle. +# Remember, the vertices are named like this: +# +# C +# / \ +# A _ B +# +# , could be changed to: +# +# B +# / \ +# A _ C +# +# if that felt more natural. +AC = Line(A, C) +CB = Line(C, B) +BA = Line(B, A) +starting_lines = [] +starting_lines.append(AC) +starting_lines.append(CB) +starting_lines.append(BA) + +# The starting depth is 0; we just need the triangle. +depth = 0 + +# For displaying the instructions. +use = "Use left and right arrows" +font_size = 36 +# Remember, colors are in RGB (Red, Green, Blue) system. +font_colour = (10, 250, 20) +font = pygame.font.Font(None, font_size) +text = font.render(use, True, font_colour) +text_box = text.get_rect() +# Where the box will be placed. +text_box.top = 100 +text_box.left = 50 + +lines = starting_lines + +while pippy.pygame.next_frame(): + for event in pygame.event.get(): + if event.type == QUIT: + sys.exit() + # When R arrow is pressed, go one step further. + # This means creating new lines on each existing line. + elif event.type == KEYDOWN and event.key == K_RIGHT and depth < 6: + lines = produce_lines(lines, 1) + depth = depth +1 + # When L arrow is pressed, go one step back, reducing the complexity of + # the snowflake. + # Basically, goes depth-1 steps forward from the starting lines. + elif event.type == KEYDOWN and event.key == K_LEFT and depth > 0: + depth = depth-1 + lines = produce_lines(starting_lines, depth) + elif event.type == KEYDOWN: + sys.exit() + screen.fill(bgcolor) + # Display the current step. + msg = "Step: " + str(depth) + "/6" + text2 = font.render(msg , True, font_colour) + text_box2 = text2.get_rect() + text_box2.top = 130 + text_box2.left = 50 + # Write the instructions and the current step on the screen. + screen.blit(text, text_box) + screen.blit(text2, text_box2) + # Draw the lines on the screen. + draw_lines(lines) + # Refresh the screen. + pygame.display.flip() + -- cgit v0.9.1