[Sugar-devel] [PATCH] Pippy example - Koch snowflake

Dinko Galetic dinko.galetic at gmail.com
Thu Jun 3 04:26:33 EDT 2010


Hi,

I've added a few new examples to Pippy. They're available in my repository (
http://git.sugarlabs.org/projects/pippy/repos/dgaletic-gsoc2010); I haven't
made an .xo since I'm having some problems with my Sugar installation.

Since this is about learning Python, in each of them I've tried to have
several places where the learner is invited to modify come code.

This one draws the Koch snowflake using pygame. The user can
decrease/increase the number of triangles with left and right arrows.

diff --git a/data/GSOC examples/Koch snowflake b/data/GSOC examples/Koch
snowfla
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
trigo
+# 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 ax
+        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()
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.sugarlabs.org/archive/sugar-devel/attachments/20100603/1f232a7c/attachment-0001.htm 


More information about the Sugar-devel mailing list