Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDinko Galetic <dgaletic@everflame.(none)>2010-06-03 07:19:18 (GMT)
committer Dinko Galetic <dgaletic@everflame.(none)>2010-06-03 07:19:18 (GMT)
commitac3ece85713b1c2b998801a51dca173cbc4216f2 (patch)
treedb013c21f1e047c7a38700ed28610c7fc054611d
parentee64655f6a54a98adfa1eab832210a082d47945e (diff)
Added a Python script which draws the Koch snowflake.
-rw-r--r--data/GSOC examples/Koch snowflake208
1 files changed, 208 insertions, 0 deletions
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()
+