patternpythonMinor
Koch snowflake in Python with numpy and pygame
Viewed 0 times
numpysnowflakewithkochpygamepythonand
Problem
I've drawn a Koch snowflake with Python 3. I'm new to the Python world and would appreciate all feedback on how to make the code more Pythonic as I'm not used to these idioms, styles and modules. All other feedback is of course also greatly appreciated.
The snowflake is constantly redrawn in preparation for the future. This main loop is based on the pygame.draw example but feels a bit clunky with
```
import pygame
import numpy
from math import pi, sin, cos
# some constants
FPS = 10
WINDOW_SIZE = [400,400]
LINE_WIDTH = 1
MIN_LINE_LENGTH = 1 # when to terminate recursion
# main loop
def main():
# init pygame and window
pygame.init()
screen = pygame.display.set_mode(WINDOW_SIZE)
# loop until user exits
done = False
clock = pygame.time.Clock()
while not done:
# limit frame rate
clock.tick(FPS)
# check if user exited
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
# clear screen
screen.fill([255,255,255])
# calculate the three corners of the snowflake,
# an equilateral triangle centered on the screen
screen_center = numpy.array([ WINDOW_SIZE[0]/2, WINDOW_SIZE[1]/2 ])
radius = WINDOW_SIZE[1]/2 # not really radius? but distance from center to corner
snowflake_top = screen_center + vector_from_polar( radius, pi/2 )
snowflake_left = screen_center + vector_from_polar( radius, pi/2 + 2*pi/3 )
snowflake_right = screen_center + vector_from_polar( radius, pi/2 + 4*pi/3 )
# draw the snowflake
draw_koch_line( screen, snowflake_top, snowflake_left )
draw_koch_line( screen, snowflake_left, snowflake_right )
draw_koch_line( screen, snowflake_right, snowflake_top )
# flip buffers
pygame.display.flip()
# vector_from_polar: constructs a vector from its angle and mangitude
def vector_from_polar( magnitude, angle )
The snowflake is constantly redrawn in preparation for the future. This main loop is based on the pygame.draw example but feels a bit clunky with
done=False;while not done etc.```
import pygame
import numpy
from math import pi, sin, cos
# some constants
FPS = 10
WINDOW_SIZE = [400,400]
LINE_WIDTH = 1
MIN_LINE_LENGTH = 1 # when to terminate recursion
# main loop
def main():
# init pygame and window
pygame.init()
screen = pygame.display.set_mode(WINDOW_SIZE)
# loop until user exits
done = False
clock = pygame.time.Clock()
while not done:
# limit frame rate
clock.tick(FPS)
# check if user exited
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
# clear screen
screen.fill([255,255,255])
# calculate the three corners of the snowflake,
# an equilateral triangle centered on the screen
screen_center = numpy.array([ WINDOW_SIZE[0]/2, WINDOW_SIZE[1]/2 ])
radius = WINDOW_SIZE[1]/2 # not really radius? but distance from center to corner
snowflake_top = screen_center + vector_from_polar( radius, pi/2 )
snowflake_left = screen_center + vector_from_polar( radius, pi/2 + 2*pi/3 )
snowflake_right = screen_center + vector_from_polar( radius, pi/2 + 4*pi/3 )
# draw the snowflake
draw_koch_line( screen, snowflake_top, snowflake_left )
draw_koch_line( screen, snowflake_left, snowflake_right )
draw_koch_line( screen, snowflake_right, snowflake_top )
# flip buffers
pygame.display.flip()
# vector_from_polar: constructs a vector from its angle and mangitude
def vector_from_polar( magnitude, angle )
Solution
This is good code — I only have a couple of minor points.
-
Since nothing changes or animates, there's no need to have a top-level loop or a clock. You can just draw the snowflake and then wait for the user to quit (calling
-
It's clearer to write
-
Instead of:
consider using the cross product:
-
There's repeated code in the computation of the triangle points that could be factored out into a function:
and then:
-
Since nothing changes or animates, there's no need to have a top-level loop or a clock. You can just draw the snowflake and then wait for the user to quit (calling
event.wait instead of event.get so that the program isn't busy doing nothing).-
It's clearer to write
pygame.Color('white') and pygame.Color('black') instead of [255, 255, 255] and [0, 0, 0].-
Instead of:
# find the normal to this line
line_normal = numpy.array([
line_end[1]-line_start[1],
line_start[0]-line_end[0] ])consider using the cross product:
line_normal = numpy.cross(line_end - line_start, [0, 0, 1])-
There's repeated code in the computation of the triangle points that could be factored out into a function:
def interpolated(x, start, end):
"""Return vector interpolated between start and end by x."""
return (1 - x) * start + x * endand then:
triangle_left = interpolated(1/3, line_start, line_end)
triangle_right = interpolated(2/3, line_start, line_end)Code Snippets
# find the normal to this line
line_normal = numpy.array([
line_end[1]-line_start[1],
line_start[0]-line_end[0] ])line_normal = numpy.cross(line_end - line_start, [0, 0, 1])def interpolated(x, start, end):
"""Return vector interpolated between start and end by x."""
return (1 - x) * start + x * endtriangle_left = interpolated(1/3, line_start, line_end)
triangle_right = interpolated(2/3, line_start, line_end)Context
StackExchange Code Review Q#129186, answer score: 4
Revisions (0)
No revisions yet.